diff options
114 files changed, 2963 insertions, 1376 deletions
diff --git a/.travis.yml b/.travis.yml index 14ee95e77e..8cfd7a1a7f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,17 +55,15 @@ matrix: packages: - *linux_deps -# TODO: Android support - -# - name: Android export template (release_debug, Clang) -# stage: build -# env: PLATFORM=android TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-clang EXTRA_ARGS="warnings=extra werror=yes" -# os: linux -# compiler: clang -# addons: -# apt: -# packages: -# - openjdk-8-jdk + - name: Android export template (release_debug, Clang) + stage: build + env: PLATFORM=android TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-clang EXTRA_ARGS="warnings=extra werror=yes" + os: linux + compiler: clang + addons: + apt: + packages: + - openjdk-8-jdk - name: macOS editor (debug, Clang) stage: build @@ -92,21 +90,6 @@ matrix: # packages: # - scons -# TODO: Dummy/Offscreen rasterizer - -# - name: Linux headless editor (release_debug, GCC 9, testing project exporting and script running) -# stage: build -# env: PLATFORM=server TOOLS=yes TARGET=release_debug CACHE_NAME=${PLATFORM}-tools-gcc-9 MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" EXTRA_ARGS="warnings=extra werror=yes" TEST_PROJECT=yes -# os: linux -# compiler: gcc-9 -# addons: -# apt: -# sources: -# - sourceline: "ppa:ubuntu-toolchain-r/test" -# packages: -# - *gcc9_deps -# - *linux_deps - - name: Linux export template (release_debug, GCC 7, without 3D support) stage: build env: PLATFORM=linuxbsd TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-gcc-7 EXTRA_ARGS="disable_3d=yes" 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/core/engine.cpp b/core/engine.cpp index 36987eab31..5361e09a8a 100644 --- a/core/engine.cpp +++ b/core/engine.cpp @@ -60,7 +60,7 @@ void Engine::set_target_fps(int p_fps) { _target_fps = p_fps > 0 ? p_fps : 0; } -float Engine::get_target_fps() const { +int Engine::get_target_fps() const { return _target_fps; } diff --git a/core/engine.h b/core/engine.h index 4cfdeffa82..8512779d4c 100644 --- a/core/engine.h +++ b/core/engine.h @@ -86,7 +86,7 @@ public: float get_physics_jitter_fix() const; virtual void set_target_fps(int p_fps); - virtual float get_target_fps() const; + virtual int get_target_fps() const; virtual float get_frames_per_second() const { return _fps; } diff --git a/core/global_constants.cpp b/core/global_constants.cpp index 8706a38453..6f6b8c1dd3 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -568,9 +568,6 @@ void register_global_constants() { BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_INTERNATIONALIZED); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_GROUP); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_CATEGORY); - //deprecated, replaced by ClassDB function to check default value - //BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONZERO); - //BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONONE); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_NO_INSTANCE_STATE); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_RESTART_IF_CHANGED); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_SCRIPT_VARIABLE); diff --git a/core/object.h b/core/object.h index 06dd610a3b..1eaab5034e 100644 --- a/core/object.h +++ b/core/object.h @@ -60,7 +60,6 @@ enum PropertyHint { PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout") PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer) - PROPERTY_HINT_SPRITE_FRAME, // FIXME: Obsolete: drop whenever we can break compat. Keeping now for GDNative compat. PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer) PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags) PROPERTY_HINT_LAYERS_2D_RENDER, diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index 8bd5a4915d..62ad3e9f98 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -511,8 +511,7 @@ void UndoRedo::_bind_methods() { ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE)); ClassDB::bind_method(D_METHOD("commit_action"), &UndoRedo::commit_action); - // FIXME: Typo in "commiting", fix in 4.0 when breaking compat. - ClassDB::bind_method(D_METHOD("is_commiting_action"), &UndoRedo::is_committing_action); + ClassDB::bind_method(D_METHOD("is_committing_action"), &UndoRedo::is_committing_action); { MethodInfo mi; diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 85a75fda37..0c8d42021a 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -838,7 +838,7 @@ Controls whether the control will be able to receive mouse button input events through [method _gui_input] and how these events should be handled. Also controls whether the control can receive the [signal mouse_entered], and [signal mouse_exited] signals. See the constants to learn what each does. </member> <member name="rect_clip_content" type="bool" setter="set_clip_contents" getter="is_clipping_contents" default="false"> - Enables whether rendering of children should be clipped to this control's rectangle. If [code]true[/code], parts of a child which would be visibly outside of this control's rectangle will not be rendered. + Enables whether rendering of [CanvasItem] based children should be clipped to this control's rectangle. If [code]true[/code], parts of a child which would be visibly outside of this control's rectangle will not be rendered. </member> <member name="rect_global_position" type="Vector2" setter="_set_global_position" getter="get_global_position"> The node's global position, relative to the world (usually to the top-left corner of the window). diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml index 540ebf3931..cf0ed8bf68 100644 --- a/doc/classes/Dictionary.xml +++ b/doc/classes/Dictionary.xml @@ -78,7 +78,7 @@ <argument index="0" name="deep" type="bool" default="false"> </argument> <description> - Creates a copy of the dictionary, and returns it. + Creates a copy of the dictionary, and returns it. The [code]deep[/code] parameter causes inner dictionaries and arrays to be copied recursively, but does not apply to objects. </description> </method> <method name="empty"> 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/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index 1db1142aa0..5b7694b775 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -43,7 +43,7 @@ <argument index="1" name="y" type="int"> </argument> <description> - Returns the coordinate of the autotile variation in the tileset. Returns a zero vector if the cell doesn't have autotiling. + Returns the coordinate (subtile column and row) of the autotile variation in the tileset. Returns a zero vector if the cell doesn't have autotiling. </description> </method> <method name="get_cellv" qualifiers="const"> @@ -161,7 +161,7 @@ <description> Sets the tile index for the cell given by a Vector2. An index of [code]-1[/code] clears the cell. - Optionally, the tile can also be flipped, transposed, or given autotile coordinates. + Optionally, the tile can also be flipped, transposed, or given autotile coordinates. The autotile coordinate refers to the column and row of the subtile. [b]Note:[/b] Data such as navigation polygons and collision shapes are not immediately updated for performance reasons. If you need these to be immediately updated, you can call [method update_dirty_quadrants]. Overriding this method also overrides it internally, allowing custom logic to be implemented when tiles are placed/removed: diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml index 766ebf7e32..2cc3e974e2 100644 --- a/doc/classes/UndoRedo.xml +++ b/doc/classes/UndoRedo.xml @@ -155,7 +155,7 @@ Returns [code]true[/code] if an "undo" action is available. </description> </method> - <method name="is_commiting_action" qualifiers="const"> + <method name="is_committing_action" qualifiers="const"> <return type="bool"> </return> <description> diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py index 9de5eac31d..c6c6cae6c0 100755 --- a/doc/tools/makerst.py +++ b/doc/tools/makerst.py @@ -424,7 +424,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S type_rst = property_def.type_name.to_rst(state) default = property_def.default_value if property_def.overridden: - ml.append((type_rst, property_def.name, "**O:** " + default)) + ml.append((type_rst, property_def.name, default + " *(parent override)*")) else: ref = ":ref:`{0}<class_{1}_property_{0}>`".format(property_def.name, class_name) ml.append((type_rst, ref, default)) 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/SCsub b/drivers/vulkan/SCsub index 35c2d61530..91d0e42f80 100644 --- a/drivers/vulkan/SCsub +++ b/drivers/vulkan/SCsub @@ -14,6 +14,14 @@ if env["platform"] == "android": thirdparty_dir + "/layers/generated", ] env.Prepend(CPPPATH=thirdparty_includes) + + # Build Vulkan memory allocator + env_thirdparty = env.Clone() + env_thirdparty.disable_warnings() + + thirdparty_dir = "#thirdparty/vulkan" + vma_sources = [thirdparty_dir + "/android/vk_mem_alloc.cpp"] + env_thirdparty.add_source_files(env.drivers_sources, vma_sources) elif env["builtin_vulkan"]: # Use bundled Vulkan headers thirdparty_dir = "#thirdparty/vulkan" 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/animation_track_editor.cpp b/editor/animation_track_editor.cpp index b393ff5fd4..f10e439f10 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -1402,7 +1402,7 @@ void AnimationTimelineEdit::_zoom_changed(double) { float AnimationTimelineEdit::get_zoom_scale() const { - float zv = zoom->get_value(); + float zv = zoom->get_max() - zoom->get_value(); if (zv < 1) { zv = 1.0 - zv; return Math::pow(1.0f + zv, 8.0f) * 100; 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/editor_themes.cpp b/editor/editor_themes.cpp index 37bca661dd..576ee436de 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -961,12 +961,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_icon("grabber", "HSlider", theme->get_icon("GuiSliderGrabber", "EditorIcons")); theme->set_stylebox("slider", "HSlider", make_flat_stylebox(dark_color_3, 0, default_margin_size / 2, 0, default_margin_size / 2)); theme->set_stylebox("grabber_area", "HSlider", make_flat_stylebox(contrast_color_1, 0, default_margin_size / 2, 0, default_margin_size / 2)); + theme->set_stylebox("grabber_area_highlight", "HSlider", make_flat_stylebox(contrast_color_1, 0, default_margin_size / 2, 0, default_margin_size / 2)); // VSlider theme->set_icon("grabber", "VSlider", theme->get_icon("GuiSliderGrabber", "EditorIcons")); theme->set_icon("grabber_highlight", "VSlider", theme->get_icon("GuiSliderGrabberHl", "EditorIcons")); theme->set_stylebox("slider", "VSlider", make_flat_stylebox(dark_color_3, default_margin_size / 2, 0, default_margin_size / 2, 0)); theme->set_stylebox("grabber_area", "VSlider", make_flat_stylebox(contrast_color_1, default_margin_size / 2, 0, default_margin_size / 2, 0)); + theme->set_stylebox("grabber_area_highlight", "VSlider", make_flat_stylebox(contrast_color_1, default_margin_size / 2, 0, default_margin_size / 2, 0)); //RichTextLabel theme->set_color("default_color", "RichTextLabel", font_color); 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/icons/ARVRAnchor.svg b/editor/icons/XRAnchor3D.svg index f1571b3fcc..f1571b3fcc 100644 --- a/editor/icons/ARVRAnchor.svg +++ b/editor/icons/XRAnchor3D.svg diff --git a/editor/icons/ARVRCamera.svg b/editor/icons/XRCamera3D.svg index f59a8c8b4a..f59a8c8b4a 100644 --- a/editor/icons/ARVRCamera.svg +++ b/editor/icons/XRCamera3D.svg diff --git a/editor/icons/ARVRController.svg b/editor/icons/XRController3D.svg index 40e5b8dce1..40e5b8dce1 100644 --- a/editor/icons/ARVRController.svg +++ b/editor/icons/XRController3D.svg diff --git a/editor/icons/ARVROrigin.svg b/editor/icons/XROrigin3D.svg index dbb93ba7a5..dbb93ba7a5 100644 --- a/editor/icons/ARVROrigin.svg +++ b/editor/icons/XROrigin3D.svg 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/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index 00e8a05e4e..eb14495b9c 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -95,6 +95,7 @@ void MaterialEditor::_button_pressed(Node *p_button) { sphere_instance->hide(); box_switch->set_pressed(true); sphere_switch->set_pressed(false); + EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", false); } if (p_button == sphere_switch) { @@ -102,6 +103,7 @@ void MaterialEditor::_button_pressed(Node *p_button) { sphere_instance->show(); box_switch->set_pressed(false); sphere_switch->set_pressed(true); + EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", true); } } @@ -155,7 +157,6 @@ MaterialEditor::MaterialEditor() { sphere_instance->set_mesh(sphere_mesh); box_mesh.instance(); box_instance->set_mesh(box_mesh); - box_instance->hide(); set_custom_minimum_size(Size2(1, 150) * EDSCALE); @@ -194,6 +195,15 @@ MaterialEditor::MaterialEditor() { light_2_switch->connect("pressed", callable_mp(this, &MaterialEditor::_button_pressed), varray(light_2_switch)); first_enter = true; + + if (EditorSettings::get_singleton()->get_project_metadata("inspector_options", "material_preview_on_sphere", true)) { + box_instance->hide(); + } else { + box_instance->show(); + sphere_instance->hide(); + box_switch->set_pressed(true); + sphere_switch->set_pressed(false); + } } /////////////////////// diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 1c16ed6b58..5c38a57cca 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; + cpu_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/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 82199fc1f1..12b21d871b 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -689,6 +689,8 @@ void ScriptCreateDialog::_update_dialog() { // Is Script created or loaded from existing file? + builtin_warning_label->set_visible(is_built_in); + if (is_built_in) { get_ok()->set_text(TTR("Create")); parent_name->set_editable(true); @@ -756,6 +758,13 @@ ScriptCreateDialog::ScriptCreateDialog() { path_error_label = memnew(Label); vb->add_child(path_error_label); + builtin_warning_label = memnew(Label); + builtin_warning_label->set_text( + TTR("Note: Built-in scripts have some limitations and can't be edited using an external editor.")); + vb->add_child(builtin_warning_label); + builtin_warning_label->set_autowrap(true); + builtin_warning_label->hide(); + status_panel = memnew(PanelContainer); status_panel->set_h_size_flags(Control::SIZE_FILL); status_panel->add_child(vb); diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index f164cd2a15..63a30eba88 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -49,6 +49,7 @@ class ScriptCreateDialog : public ConfirmationDialog { LineEdit *class_name; Label *error_label; Label *path_error_label; + Label *builtin_warning_label; PanelContainer *status_panel; LineEdit *parent_name; Button *parent_browse_button; diff --git a/main/main.cpp b/main/main.cpp index 92f40588f2..fb42f71a75 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -478,6 +478,14 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph I = args.front(); while (I) { +#ifdef OSX_ENABLED + // Ignore the process serial number argument passed by macOS Gatekeeper. + // Otherwise, Godot would try to open a non-existent project on the first start and abort. + if (I->get().begins_with("-psn_")) { + I = I->next(); + continue; + } +#endif List<String>::Element *N = I->next(); diff --git a/misc/travis/android-tools-linux.sh b/misc/travis/android-tools-linux.sh index d0c123ee6c..4eeb54412c 100755 --- a/misc/travis/android-tools-linux.sh +++ b/misc/travis/android-tools-linux.sh @@ -24,12 +24,12 @@ ANDROID_SDK_URL=$ANDROID_BASE_URL/$ANDROID_SDK_FILENAME ANDROID_SDK_PATH=$GODOT_BUILD_TOOLS_PATH/$ANDROID_SDK_DIR ANDROID_SDK_SHA256=92ffee5a1d98d856634e8b71132e8a95d96c83a63fde1099be3d86df3106def9 -ANDROID_NDK_RELEASE=r20 +ANDROID_NDK_RELEASE=r21 ANDROID_NDK_DIR=android-ndk ANDROID_NDK_FILENAME=android-ndk-$ANDROID_NDK_RELEASE-linux-x86_64.zip ANDROID_NDK_URL=$ANDROID_BASE_URL/$ANDROID_NDK_FILENAME ANDROID_NDK_PATH=$GODOT_BUILD_TOOLS_PATH/$ANDROID_NDK_DIR -ANDROID_NDK_SHA1=8665fc84a1b1f0d6ab3b5fdd1e30200cc7b9adff +ANDROID_NDK_SHA1=afc9c0b9faad222898ac8168c78ad4ccac8a1b5c echo echo "Download and install Android development tools ..." diff --git a/modules/gdnative/include/nativescript/godot_nativescript.h b/modules/gdnative/include/nativescript/godot_nativescript.h index 1b131c8cf0..dcf2ddb9ca 100644 --- a/modules/gdnative/include/nativescript/godot_nativescript.h +++ b/modules/gdnative/include/nativescript/godot_nativescript.h @@ -54,7 +54,6 @@ typedef enum { GODOT_PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc" GODOT_PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) GODOT_PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer) - GODOT_PROPERTY_HINT_SPRITE_FRAME, // FIXME: Obsolete: drop whenever we can break compat GODOT_PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer) GODOT_PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags) GODOT_PROPERTY_HINT_LAYERS_2D_RENDER, @@ -96,8 +95,6 @@ typedef enum { GODOT_PROPERTY_USAGE_INTERNATIONALIZED = 64, //hint for internationalized strings GODOT_PROPERTY_USAGE_GROUP = 128, //used for grouping props in the editor GODOT_PROPERTY_USAGE_CATEGORY = 256, - GODOT_PROPERTY_USAGE_STORE_IF_NONZERO = 512, // FIXME: Obsolete: drop whenever we can break compat - GODOT_PROPERTY_USAGE_STORE_IF_NONONE = 1024, // FIXME: Obsolete: drop whenever we can break compat GODOT_PROPERTY_USAGE_NO_INSTANCE_STATE = 2048, GODOT_PROPERTY_USAGE_RESTART_IF_CHANGED = 4096, GODOT_PROPERTY_USAGE_SCRIPT_VARIABLE = 8192, diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index a99d4b96f7..8d34ce5c70 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -7364,6 +7364,8 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN } } +#define IS_USAGE_MEMBER(m_usage) (!(m_usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY))) + // Check other script types while (scr.is_valid()) { Map<StringName, Variant> constants; @@ -7376,7 +7378,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN List<PropertyInfo> properties; scr->get_script_property_list(&properties); for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - if (E->get().name == p_member) { + if (E->get().name == p_member && IS_USAGE_MEMBER(E->get().usage)) { r_member_type = _type_from_property(E->get()); return true; } @@ -7418,7 +7420,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN List<PropertyInfo> properties; ClassDB::get_property_list(native, &properties); for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - if (E->get().name == p_member) { + if (E->get().name == p_member && IS_USAGE_MEMBER(E->get().usage)) { // Check if a getter exists StringName getter_name = ClassDB::get_property_getter(native, p_member); if (getter_name != StringName()) { @@ -7458,7 +7460,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN List<PropertyInfo> properties; ClassDB::get_property_list(native, &properties); for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - if (E->get().name == p_member) { + if (E->get().name == p_member && IS_USAGE_MEMBER(E->get().usage)) { // Check if a getter exists StringName getter_name = ClassDB::get_property_getter(native, p_member); if (getter_name != StringName()) { @@ -7480,6 +7482,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN } } } +#undef IS_USAGE_MEMBER return false; } diff --git a/modules/opensimplex/noise_texture.cpp b/modules/opensimplex/noise_texture.cpp index ec67030a65..2018f90e9f 100644 --- a/modules/opensimplex/noise_texture.cpp +++ b/modules/opensimplex/noise_texture.cpp @@ -137,14 +137,19 @@ void NoiseTexture::_queue_update() { Ref<Image> NoiseTexture::_generate_texture() { - if (noise.is_null()) return Ref<Image>(); + // Prevent memdelete due to unref() on other thread. + Ref<OpenSimplexNoise> ref_noise = noise; + + if (ref_noise.is_null()) { + return Ref<Image>(); + } Ref<Image> image; if (seamless) { - image = noise->get_seamless_image(size.x); + image = ref_noise->get_seamless_image(size.x); } else { - image = noise->get_image(size.x, size.y); + image = ref_noise->get_image(size.x, size.y); } if (as_normalmap) { 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_editor.cpp b/modules/visual_script/visual_script_editor.cpp index ab528fac30..59b1bcdd96 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -350,8 +350,11 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) { case Variant::STRING: color = Color(0.42, 0.65, 0.93); break; case Variant::VECTOR2: color = Color(0.74, 0.57, 0.95); break; + case Variant::VECTOR2I: color = Color(0.74, 0.57, 0.95); break; case Variant::RECT2: color = Color(0.95, 0.57, 0.65); break; + case Variant::RECT2I: color = Color(0.95, 0.57, 0.65); break; case Variant::VECTOR3: color = Color(0.84, 0.49, 0.93); break; + case Variant::VECTOR3I: color = Color(0.84, 0.49, 0.93); break; case Variant::TRANSFORM2D: color = Color(0.77, 0.93, 0.41); break; case Variant::PLANE: color = Color(0.97, 0.44, 0.44); break; case Variant::QUAT: color = Color(0.93, 0.41, 0.64); break; @@ -389,8 +392,11 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) { case Variant::STRING: color = Color(0.27, 0.56, 0.91); break; case Variant::VECTOR2: color = Color(0.68, 0.46, 0.93); break; + case Variant::VECTOR2I: color = Color(0.68, 0.46, 0.93); break; case Variant::RECT2: color = Color(0.93, 0.46, 0.56); break; + case Variant::RECT2I: color = Color(0.93, 0.46, 0.56); break; case Variant::VECTOR3: color = Color(0.86, 0.42, 0.93); break; + case Variant::VECTOR3I: color = Color(0.86, 0.42, 0.93); break; case Variant::TRANSFORM2D: color = Color(0.59, 0.81, 0.1); break; case Variant::PLANE: color = Color(0.97, 0.44, 0.44); break; case Variant::QUAT: color = Color(0.93, 0.41, 0.64); break; @@ -510,8 +516,11 @@ void VisualScriptEditor::_update_graph(int p_only_id) { Control::get_theme_icon("float", "EditorIcons"), Control::get_theme_icon("String", "EditorIcons"), Control::get_theme_icon("Vector2", "EditorIcons"), + Control::get_theme_icon("Vector2i", "EditorIcons"), Control::get_theme_icon("Rect2", "EditorIcons"), + Control::get_theme_icon("Rect2i", "EditorIcons"), Control::get_theme_icon("Vector3", "EditorIcons"), + Control::get_theme_icon("Vector3i", "EditorIcons"), Control::get_theme_icon("Transform2D", "EditorIcons"), Control::get_theme_icon("Plane", "EditorIcons"), Control::get_theme_icon("Quat", "EditorIcons"), @@ -522,6 +531,8 @@ void VisualScriptEditor::_update_graph(int p_only_id) { Control::get_theme_icon("NodePath", "EditorIcons"), Control::get_theme_icon("RID", "EditorIcons"), Control::get_theme_icon("MiniObject", "EditorIcons"), + Control::get_theme_icon("Callable", "EditorIcons"), + Control::get_theme_icon("Signal", "EditorIcons"), Control::get_theme_icon("Dictionary", "EditorIcons"), Control::get_theme_icon("Array", "EditorIcons"), Control::get_theme_icon("PackedByteArray", "EditorIcons"), @@ -974,8 +985,11 @@ void VisualScriptEditor::_update_members() { Control::get_theme_icon("float", "EditorIcons"), Control::get_theme_icon("String", "EditorIcons"), Control::get_theme_icon("Vector2", "EditorIcons"), + Control::get_theme_icon("Vector2i", "EditorIcons"), Control::get_theme_icon("Rect2", "EditorIcons"), + Control::get_theme_icon("Rect2i", "EditorIcons"), Control::get_theme_icon("Vector3", "EditorIcons"), + Control::get_theme_icon("Vector3i", "EditorIcons"), Control::get_theme_icon("Transform2D", "EditorIcons"), Control::get_theme_icon("Plane", "EditorIcons"), Control::get_theme_icon("Quat", "EditorIcons"), @@ -986,6 +1000,8 @@ void VisualScriptEditor::_update_members() { Control::get_theme_icon("NodePath", "EditorIcons"), Control::get_theme_icon("RID", "EditorIcons"), Control::get_theme_icon("MiniObject", "EditorIcons"), + Control::get_theme_icon("Callable", "EditorIcons"), + Control::get_theme_icon("Signal", "EditorIcons"), Control::get_theme_icon("Dictionary", "EditorIcons"), Control::get_theme_icon("Array", "EditorIcons"), Control::get_theme_icon("PackedByteArray", "EditorIcons"), @@ -1155,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(); @@ -3917,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: { @@ -4629,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/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 97c2686cd5..c860e08943 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -4184,9 +4184,12 @@ void register_visual_script_nodes() { VisualScriptLanguage::singleton->add_register_func("operators/logic/select", create_node_generic<VisualScriptSelect>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR2), create_node_deconst_typed<Variant::Type::VECTOR2>); + VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR2I), create_node_deconst_typed<Variant::Type::VECTOR2I>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR3), create_node_deconst_typed<Variant::Type::VECTOR3>); + VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR3I), create_node_deconst_typed<Variant::Type::VECTOR3I>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::COLOR), create_node_deconst_typed<Variant::Type::COLOR>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::RECT2), create_node_deconst_typed<Variant::Type::RECT2>); + VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::RECT2I), create_node_deconst_typed<Variant::Type::RECT2I>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM2D), create_node_deconst_typed<Variant::Type::TRANSFORM2D>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::PLANE), create_node_deconst_typed<Variant::Type::PLANE>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::QUAT), create_node_deconst_typed<Variant::Type::QUAT>); 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/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/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/platform/android/vulkan/vulkan_context_android.cpp b/platform/android/vulkan/vulkan_context_android.cpp index b238f849fc..5fb7a83da4 100644 --- a/platform/android/vulkan/vulkan_context_android.cpp +++ b/platform/android/vulkan/vulkan_context_android.cpp @@ -31,14 +31,6 @@ #include "vulkan_context_android.h" #include <vulkan/vulkan_android.h> -#define VMA_IMPLEMENTATION -#ifdef DEBUG_ENABLED -#ifndef _DEBUG -#define _DEBUG -#endif -#endif -#include <vk_mem_alloc.h> - const char *VulkanContextAndroid::_get_platform_surface_extension() const { return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; } diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 47497eb95f..6049dbf4d6 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -254,10 +254,10 @@ bool DisplayServerX11::_refresh_device_info() { bool absolute_mode = false; int resolution_x = 0; int resolution_y = 0; - int range_min_x = 0; - int range_min_y = 0; - int range_max_x = 0; - int range_max_y = 0; + double range_min_x = 0; + double range_min_y = 0; + double range_max_x = 0; + double range_max_y = 0; int pressure_resolution = 0; int tilt_resolution_x = 0; int tilt_resolution_y = 0; 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 c822b70a4b..81a5c6f4f3 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -216,6 +216,14 @@ bool Light3D::is_editor_only() const { } void Light3D::_validate_property(PropertyInfo &property) const { + + if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_size") { + property.usage = 0; + } + + if (get_light_type() != RS::LIGHT_DIRECTIONAL && property.name == "light_angular_distance") { + property.usage = 0; + } } void Light3D::_bind_methods() { @@ -251,6 +259,8 @@ void Light3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_ENERGY); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_INDIRECT_ENERGY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_size", PROPERTY_HINT_RANGE, "0,64,0.01,or_greater"), "set_param", "get_param", PARAM_SIZE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_angular_distance", PROPERTY_HINT_RANGE, "0,90,0.01"), "set_param", "get_param", PARAM_SIZE); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SPECULAR); ADD_PROPERTY(PropertyInfo(Variant::INT, "light_bake_mode", PROPERTY_HINT_ENUM, "Disable,Indirect,All"), "set_bake_mode", "get_bake_mode"); @@ -262,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("", ""); @@ -281,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); @@ -315,6 +327,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) { set_param(PARAM_INDIRECT_ENERGY, 1); set_param(PARAM_SPECULAR, 0.5); set_param(PARAM_RANGE, 5); + set_param(PARAM_SIZE, 0); set_param(PARAM_ATTENUATION, 1); set_param(PARAM_SPOT_ANGLE, 45); set_param(PARAM_SPOT_ATTENUATION, 1); @@ -324,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 ad2a1d5a84..21e14f0e8b 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -46,6 +46,7 @@ public: PARAM_INDIRECT_ENERGY = RS::LIGHT_PARAM_INDIRECT_ENERGY, PARAM_SPECULAR = RS::LIGHT_PARAM_SPECULAR, PARAM_RANGE = RS::LIGHT_PARAM_RANGE, + PARAM_SIZE = RS::LIGHT_PARAM_SIZE, PARAM_ATTENUATION = RS::LIGHT_PARAM_ATTENUATION, PARAM_SPOT_ANGLE = RS::LIGHT_PARAM_SPOT_ANGLE, PARAM_SPOT_ATTENUATION = RS::LIGHT_PARAM_SPOT_ATTENUATION, @@ -57,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/slider.cpp b/scene/gui/slider.cpp index e47e2b869d..1f135163d4 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -166,8 +166,9 @@ void Slider::_notification(int p_what) { RID ci = get_canvas_item(); Size2i size = get_size(); Ref<StyleBox> style = get_theme_stylebox("slider"); - Ref<StyleBox> grabber_area = get_theme_stylebox("grabber_area"); - Ref<Texture2D> grabber = get_theme_icon(editable ? ((mouse_inside || has_focus()) ? "grabber_highlight" : "grabber") : "grabber_disabled"); + bool highlighted = mouse_inside || has_focus(); + Ref<StyleBox> grabber_area = get_theme_stylebox(highlighted ? "grabber_area_highlight" : "grabber_area"); + Ref<Texture2D> grabber = get_theme_icon(editable ? (highlighted ? "grabber_highlight" : "grabber") : "grabber_disabled"); Ref<Texture2D> tick = get_theme_icon("tick"); double ratio = Math::is_nan(get_as_ratio()) ? 0 : get_as_ratio(); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index a7acaae8df..509a52d36a 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -3045,13 +3045,6 @@ void Tree::_notification(int p_what) { draw_item(Point2(), draw_ofs, draw_size, root); } - int ofs = 0; - - for (int i = 0; i < (columns.size() - 1 - 1); i++) { - - ofs += get_column_width(i); - } - if (show_column_titles) { //title buttons 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/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index e6f09eb034..a1e8bf51bd 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -497,6 +497,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("slider", "HSlider", make_stylebox(hslider_bg_png, 4, 4, 4, 4)); theme->set_stylebox("grabber_area", "HSlider", make_stylebox(hslider_bg_png, 4, 4, 4, 4)); + theme->set_stylebox("grabber_area_highlight", "HSlider", make_stylebox(hslider_bg_png, 4, 4, 4, 4)); theme->set_icon("grabber", "HSlider", make_icon(hslider_grabber_png)); theme->set_icon("grabber_highlight", "HSlider", make_icon(hslider_grabber_hl_png)); @@ -507,6 +508,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("slider", "VSlider", make_stylebox(vslider_bg_png, 4, 4, 4, 4)); theme->set_stylebox("grabber_area", "VSlider", make_stylebox(vslider_bg_png, 4, 4, 4, 4)); + theme->set_stylebox("grabber_area_highlight", "VSlider", make_stylebox(vslider_bg_png, 4, 4, 4, 4)); theme->set_icon("grabber", "VSlider", make_icon(vslider_grabber_png)); theme->set_icon("grabber_highlight", "VSlider", make_icon(vslider_grabber_hl_png)); diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h index b553cf0670..a6b18ee33c 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 5013b38f3f..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; @@ -231,7 +232,7 @@ public: virtual RID light_instance_create(RID p_light) = 0; virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) = 0; - virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0) = 0; + virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0; virtual void light_instance_mark_visible(RID p_light_instance) = 0; virtual bool light_instances_can_render_shadow_cube() const { return true; @@ -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..c34eb4cd79 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; + + 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(); +} - zeromem(&blur.push_constant, sizeof(BlurPushConstant)); +void RasterizerEffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y) { - 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; + 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; - 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.section[2] = p_size.x; + copy.push_constant.section[3] = p_size.y; - blur.push_constant.glow_auto_exposure_grey = p_auto_exposure_grey; //unused also + 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; + + 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,9 @@ 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); + bokeh.shader.version_free(bokeh.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 8d9b352a85..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); + } + + } 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()); - specular_only_fb = RD::get_singleton()->framebuffer_create(fb); + { + 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); + 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); + } } } @@ -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,19 @@ 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; + 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; @@ -1484,6 +1637,10 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig light_data.specular = storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR); light_data.mask = storage->light_get_cull_mask(base); + float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); + + light_data.size = 1.0 - Math::cos(Math::deg2rad(size)); //angle to cosine offset + Color shadow_col = storage->light_get_shadow_color(base).to_linear(); if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS) { @@ -1551,12 +1708,47 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig light_data.shadow_normal_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * light_instance_get_directional_shadow_texel_size(li, j); light_data.shadow_transmittance_bias[j] = storage->light_get_transmittance_bias(base) * bias_scale; light_data.shadow_transmittance_z_scale[j] = light_instance_get_shadow_range(li, j); + light_data.shadow_range_begin[j] = light_instance_get_shadow_range_begin(li, j); store_camera(shadow_mtx, light_data.shadow_matrices[j]); + + Vector2 uv_scale = light_instance_get_shadow_uv_scale(li, j); + uv_scale *= atlas_rect.size; //adapt to atlas size + switch (j) { + case 0: { + light_data.uv_scale1[0] = uv_scale.x; + light_data.uv_scale1[1] = uv_scale.y; + } break; + case 1: { + light_data.uv_scale2[0] = uv_scale.x; + light_data.uv_scale2[1] = uv_scale.y; + } break; + case 2: { + light_data.uv_scale3[0] = uv_scale.x; + light_data.uv_scale3[1] = uv_scale.y; + } break; + case 3: { + light_data.uv_scale4[0] = uv_scale.x; + light_data.uv_scale4[1] = uv_scale.y; + } break; + } } float fade_start = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_FADE_START); 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. + // technically this will keep expanding until reaching the sun, but all we care + // is expand until we reach the radius of the near plane (there can't be more occluders than that) + 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 + } } // Copy to SkyDirectionalLightData @@ -1619,6 +1811,10 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig light_data.direction[1] = direction.y; light_data.direction[2] = direction.z; + float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); + + light_data.size = size; + light_data.cone_attenuation_angle[0] = Math::make_half_float(storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION)); float spot_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE); light_data.cone_attenuation_angle[1] = Math::make_half_float(Math::cos(Math::deg2rad(spot_angle))); @@ -1646,6 +1842,7 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig shadow_texel_size *= light_instance_get_shadow_texel_size(li, p_shadow_atlas); light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size; + } else { //omni light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0; float shadow_texel_size = light_instance_get_shadow_texel_size(li, p_shadow_atlas); @@ -1656,18 +1853,34 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig Rect2 rect = light_instance_get_shadow_atlas_rect(li, p_shadow_atlas); - if (type == RS::LIGHT_OMNI) { + light_data.atlas_rect[0] = rect.position.x; + light_data.atlas_rect[1] = rect.position.y; + light_data.atlas_rect[2] = rect.size.width; + light_data.atlas_rect[3] = rect.size.height; - light_data.atlas_rect[0] = rect.position.x; - light_data.atlas_rect[1] = rect.position.y; - light_data.atlas_rect[2] = rect.size.width; - light_data.atlas_rect[3] = rect.size.height * 0.5; + 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 Transform proj = (p_camera_inverse_transform * light_transform).inverse(); store_transform(proj, light_data.shadow_matrix); + + if (size > 0.0) { + + 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) { + //used for clamping in this light type + light_data.atlas_rect[2] += light_data.atlas_rect[0]; + light_data.atlas_rect[3] += light_data.atlas_rect[1]; + Transform modelview = (p_camera_inverse_transform * light_transform).inverse(); CameraMatrix bias; bias.set_light_bias(); @@ -1676,6 +1889,15 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig CameraMatrix shadow_mtx = rectm * bias * light_instance_get_shadow_camera(li, 0) * modelview; store_camera(shadow_mtx, light_data.shadow_matrix); + + if (size > 0.0) { + CameraMatrix cm = light_instance_get_shadow_camera(li, 0); + float half_np = cm.get_z_near() * Math::tan(Math::deg2rad(spot_angle)); + 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 { light_data.shadow_color_enabled[3] = 0; @@ -1714,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"); @@ -1774,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; @@ -1935,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) { @@ -2017,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) { @@ -2026,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()); } } @@ -2048,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 b89de11bb4..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; @@ -254,17 +265,20 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { float position[3]; float inv_radius; float direction[3]; + float size; uint16_t attenuation_energy[2]; //16 bits attenuation, then energy uint8_t color_specular[4]; //rgb color, a specular (8 bit unorm) uint16_t cone_attenuation_angle[2]; // attenuation and angle, (16bit float) - uint32_t mask; uint8_t shadow_color_enabled[4]; //shadow rgb color, a>0.5 enabled (8bit unorm) float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv float shadow_matrix[16]; float shadow_bias; float shadow_normal_bias; float transmittance_bias; - uint32_t pad; + float soft_shadow_size; + float soft_shadow_scale; + uint32_t mask; + uint32_t pad[2]; }; struct DirectionalLightData { @@ -272,9 +286,11 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { float direction[3]; float energy; float color[3]; + float size; float specular; uint32_t mask; - uint32_t pad[3]; + float softshadow_angle; + float soft_shadow_scale; uint32_t blend_splits; uint32_t shadow_enabled; float fade_from; @@ -283,12 +299,17 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { float shadow_normal_bias[4]; float shadow_transmittance_bias[4]; float shadow_transmittance_z_scale[4]; + float shadow_range_begin[4]; float shadow_split_offsets[4]; float shadow_matrices[4][16]; float shadow_color1[4]; float shadow_color2[4]; float shadow_color3[4]; float shadow_color4[4]; + float uv_scale1[2]; + float uv_scale2[2]; + float uv_scale3[2]; + float uv_scale4[2]; }; struct GIProbeData { @@ -341,7 +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 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 deef34d71f..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(); @@ -2032,7 +2034,7 @@ void RasterizerSceneRD::light_instance_set_transform(RID p_light_instance, const light_instance->transform = p_transform; } -void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale) { +void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); ERR_FAIL_COND(!light_instance); @@ -2048,7 +2050,9 @@ void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance light_instance->shadow_transform[p_pass].farplane = p_far; light_instance->shadow_transform[p_pass].split = p_split; light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale; + light_instance->shadow_transform[p_pass].range_begin = p_range_begin; light_instance->shadow_transform[p_pass].shadow_texel_size = p_shadow_texel_size; + light_instance->shadow_transform[p_pass].uv_scale = p_uv_scale; } void RasterizerSceneRD::light_instance_mark_visible(RID p_light_instance) { @@ -3060,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()); @@ -3077,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; @@ -3091,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); } @@ -3422,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); } } } @@ -3457,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; @@ -3480,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); } } @@ -3489,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); } } @@ -3497,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); } } @@ -3535,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); { @@ -3549,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()); } @@ -3560,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()); } @@ -3581,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 { @@ -3626,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; @@ -3700,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 @@ -3727,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); @@ -3783,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 @@ -3794,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 @@ -4143,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() { @@ -4182,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 94c7971ec3..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; @@ -573,7 +584,9 @@ private: float split; float bias_scale; float shadow_texel_size; + float range_begin; Rect2 atlas_rect; + Vector2 uv_scale; }; RS::LightType light_type = RS::LIGHT_DIRECTIONAL; @@ -715,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; @@ -728,7 +743,6 @@ private: struct Mipmap { RID texture; - RID framebuffer; int width; int height; }; @@ -883,7 +897,7 @@ public: RID light_instance_create(RID p_light); void light_instance_set_transform(RID p_light_instance, const Transform &p_transform); - void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0); + void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()); void light_instance_mark_visible(RID p_light_instance); _FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) { @@ -967,6 +981,17 @@ public: LightInstance *li = light_instance_owner.getornull(p_light_instance); return li->shadow_transform[p_index].farplane; } + _FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) { + + LightInstance *li = light_instance_owner.getornull(p_light_instance); + return li->shadow_transform[p_index].range_begin; + } + + _FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) { + + LightInstance *li = light_instance_owner.getornull(p_light_instance); + return li->shadow_transform[p_index].uv_scale; + } _FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) { @@ -1138,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); @@ -1164,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 8c73cecec3..6ac1f7c95e 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp @@ -3104,6 +3104,7 @@ RID RasterizerStorageRD::light_create(RS::LightType p_type) { light.param[RS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0; light.param[RS::LIGHT_PARAM_SPECULAR] = 0.5; light.param[RS::LIGHT_PARAM_RANGE] = 1.0; + light.param[RS::LIGHT_PARAM_SIZE] = 0.0; light.param[RS::LIGHT_PARAM_SPOT_ANGLE] = 45; light.param[RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE] = 0; light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1; @@ -3913,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); @@ -4027,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++) { @@ -4045,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); } { @@ -4059,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); @@ -4137,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); @@ -4187,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; } } @@ -4646,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 62ab188ddc..ea9d50c11d 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl @@ -441,7 +441,7 @@ vec3 F0(float metallic, float specular, vec3 albedo) { return mix(vec3(dielectric), albedo, vec3(metallic)); } -void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3 shadow_attenuation, vec3 diffuse_color, float roughness, float metallic, float specular, float specular_blob_intensity, +void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 shadow_attenuation, vec3 diffuse_color, float roughness, float metallic, float specular, float specular_blob_intensity, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -481,7 +481,7 @@ LIGHT_SHADER_CODE /* clang-format on */ #else - float NdotL = dot(N, L); + float NdotL = min(A + dot(N, L), 1.0); float cNdotL = max(NdotL, 0.0); // clamped NdotL float NdotV = dot(N, V); float cNdotV = max(NdotV, 0.0); @@ -491,11 +491,11 @@ LIGHT_SHADER_CODE #endif #if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) - float cNdotH = max(dot(N, H), 0.0); + float cNdotH = clamp(A + dot(N, H), 0.0, 1.0); #endif #if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) - float cLdotH = max(dot(L, H), 0.0); + float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); #endif if (metallic < 1.0) { @@ -613,7 +613,7 @@ LIGHT_SHADER_CODE #elif defined(SPECULAR_PHONG) vec3 R = normalize(-reflect(L, N)); - float cRdotV = max(0.0, dot(R, V)); + float cRdotV = clamp(A + dot(R, V), 0.0, 1.0); float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; float phong = pow(cRdotV, shininess); phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); @@ -686,43 +686,108 @@ LIGHT_SHADER_CODE #ifndef USE_NO_SHADOWS -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; + + //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 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; - 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.soft_shadow_samples == 1) { + return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); } - return 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) { + + //find blocker + float blocker_count = 0.0; + float blocker_average = 0.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)); + } + + 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; + blocker_count += 1.0; + } + } + + if (blocker_count > 0.0) { + + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (pssm_coord.z - blocker_average) / blocker_average; + tex_scale *= penumbra; + + float s = 0.0; + 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.directional_penumbra_shadow_samples); + + } else { + //no blockers found, so no shadow + return 1.0; + } } #endif //USE_NO_SHADOWS @@ -760,6 +825,13 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a vec3 shadow_attenuation = vec3(1.0); vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular); color_specular.rgb *= attenuation_energy.y; + float size_A = 0.0; + + if (lights.data[idx].size > 0.0) { + + float t = lights.data[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } #ifdef LIGHT_TRANSMITTANCE_USED float transmittance_z = transmittance_depth; //no transmittance by default @@ -773,7 +845,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a vec4 v = vec4(vertex, 1.0); vec4 splane = (lights.data[idx].shadow_matrix * v); - float shadow_len = length(splane.xyz); + float shadow_len = length(splane.xyz); //need to remember shadow len from here { vec3 nofs = normal_interp * lights.data[idx].shadow_normal_bias / lights.data[idx].inv_radius; @@ -782,30 +854,133 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a splane = (lights.data[idx].shadow_matrix * v); } - splane.xyz = normalize(splane.xyz); - vec4 clamp_rect = lights.data[idx].atlas_rect; + float shadow; + + if (lights.data[idx].soft_shadow_size > 0.0) { + //soft shadow + + //find blocker + + float blocker_count = 0.0; + float blocker_average = 0.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)); + } + + vec3 normal = normalize(splane.xyz); + vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); + vec3 tangent = normalize(cross(v0, normal)); + vec3 bitangent = normalize(cross(tangent, normal)); + float z_norm = shadow_len * lights.data[idx].inv_radius; + + 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++) { - if (splane.z >= 0.0) { + vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; - splane.z += 1.0; + vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; - clamp_rect.y += clamp_rect.w; + pos = normalize(pos); + vec4 uv_rect = lights.data[idx].atlas_rect; + + if (pos.z >= 0.0) { + + pos.z += 1.0; + uv_rect.y += uv_rect.w; + } else { + + pos.z = 1.0 - pos.z; + } + + pos.xy /= pos.z; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + + float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), pos.xy, 0.0).r; + if (d < z_norm) { + blocker_average += d; + blocker_count += 1.0; + } + } + + if (blocker_count > 0.0) { + + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (z_norm - blocker_average) / blocker_average; + tangent *= penumbra; + bitangent *= penumbra; + + z_norm -= lights.data[idx].inv_radius * lights.data[idx].shadow_bias; + + shadow = 0.0; + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + + 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; + + if (pos.z >= 0.0) { + + pos.z += 1.0; + uv_rect.y += uv_rect.w; + } else { + + pos.z = 1.0 - pos.z; + } + + pos.xy /= pos.z; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0)); + } + shadow /= float(scene_data.penumbra_shadow_samples); + + } else { + //no blockers found, so no shadow + shadow = 1.0; + } } else { - splane.z = 1.0 - splane.z; - } - splane.xy /= splane.z; + splane.xyz = normalize(splane.xyz); + vec4 clamp_rect = lights.data[idx].atlas_rect; + + if (splane.z >= 0.0) { + + splane.z += 1.0; + + clamp_rect.y += clamp_rect.w; + + } else { + splane.z = 1.0 - splane.z; + } + + splane.xy /= splane.z; - splane.xy = splane.xy * 0.5 + 0.5; - 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 - float shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane); + splane.xy = splane.xy * 0.5 + 0.5; + 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_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)); @@ -836,7 +1011,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a } #endif //USE_NO_SHADOWS - light_compute(normal, normalize(light_rel_vec), eye_vec, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, + light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -903,6 +1078,13 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular); color_specular.rgb *= attenuation_energy.y; + float size_A = 0.0; + + if (lights.data[idx].size > 0.0) { + + float t = lights.data[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } /* if (lights.data[idx].atlas_rect!=vec4(0.0)) { //use projector texture @@ -920,22 +1102,82 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a v.xyz -= spot_dir * lights.data[idx].shadow_bias; - float depth_bias_scale = 1.0 / (max(0.0001, dot(spot_dir, -light_rel_vec) * lights.data[idx].inv_radius)); //the closer to the light origin, the more you have to offset to reach 1px in the map + float z_norm = dot(spot_dir, -light_rel_vec) * lights.data[idx].inv_radius; + + float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * lights.data[idx].shadow_normal_bias * depth_bias_scale; normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z v.xyz += normal_bias; + //adjust with bias + z_norm = dot(spot_dir, v.xyz - lights.data[idx].position) * lights.data[idx].inv_radius; + + float shadow; + vec4 splane = (lights.data[idx].shadow_matrix * v); splane /= splane.w; - splane.z = dot(spot_dir, v.xyz - lights.data[idx].position) * lights.data[idx].inv_radius; - float shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane); + + if (lights.data[idx].soft_shadow_size > 0.0) { + //soft shadow + + //find blocker + + float blocker_count = 0.0; + float blocker_average = 0.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 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) { + blocker_average += d; + blocker_count += 1.0; + } + } + + if (blocker_count > 0.0) { + + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (z_norm - blocker_average) / blocker_average; + uv_size *= penumbra; + + shadow = 0.0; + 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.penumbra_shadow_samples); + + } else { + //no blockers found, so no shadow + shadow = 1.0; + } + + } else { + //hard shadow + splane.z = z_norm; + 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); #ifdef LIGHT_TRANSMITTANCE_USED { - splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0)); + vec4 splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0)); splane /= splane.w; float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; @@ -950,7 +1192,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a #endif //USE_NO_SHADOWS - light_compute(normal, normalize(light_rel_vec), eye_vec, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, + light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1636,13 +1878,28 @@ FRAGMENT_SHADER_CODE normal_bias -= light_dir * dot(light_dir, normal_bias); \ m_var.xyz += normal_bias; + float shadow = 0.0; + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { vec4 v = vec4(vertex, 1.0); BIAS_FUNC(v, 0) pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + 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 * directional_lights.data[i].soft_shadow_scale); + } else { + 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; + #ifdef LIGHT_TRANSMITTANCE_USED { vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0); @@ -1663,6 +1920,18 @@ FRAGMENT_SHADER_CODE BIAS_FUNC(v, 1) pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + 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 * directional_lights.data[i].soft_shadow_scale); + } else { + 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; #ifdef LIGHT_TRANSMITTANCE_USED { @@ -1684,6 +1953,18 @@ FRAGMENT_SHADER_CODE BIAS_FUNC(v, 2) pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + 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 * directional_lights.data[i].soft_shadow_scale); + } else { + 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; #ifdef LIGHT_TRANSMITTANCE_USED { @@ -1706,7 +1987,20 @@ FRAGMENT_SHADER_CODE BIAS_FUNC(v, 3) pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + 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 * directional_lights.data[i].soft_shadow_scale); + } else { + 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; + #ifdef LIGHT_TRANSMITTANCE_USED { vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0); @@ -1722,40 +2016,72 @@ FRAGMENT_SHADER_CODE #endif } - pssm_coord /= pssm_coord.w; - - float shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); - if (directional_lights.data[i].blend_splits) { vec3 shadow_color_blend = vec3(0.0); float pssm_blend; + float shadow2; if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { vec4 v = vec4(vertex, 1.0); BIAS_FUNC(v, 1) pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + 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 * directional_lights.data[i].soft_shadow_scale); + } else { + 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); shadow_color_blend = directional_lights.data[i].shadow_color2.rgb; } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { vec4 v = vec4(vertex, 1.0); BIAS_FUNC(v, 2) pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + 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 * directional_lights.data[i].soft_shadow_scale); + } else { + 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); + shadow_color_blend = directional_lights.data[i].shadow_color3.rgb; } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { vec4 v = vec4(vertex, 1.0); BIAS_FUNC(v, 3) pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); + pssm_coord /= pssm_coord.w; + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + 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 * directional_lights.data[i].soft_shadow_scale); + } else { + 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); shadow_color_blend = directional_lights.data[i].shadow_color4.rgb; } else { pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached) } - pssm_coord /= pssm_coord.w; + pssm_blend = sqrt(pssm_blend); - float shadow2 = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); shadow = mix(shadow, shadow2, pssm_blend); shadow_color = mix(shadow_color, shadow_color_blend, pssm_blend); } @@ -1767,7 +2093,7 @@ FRAGMENT_SHADER_CODE #undef BIAS_FUNC } - light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, 1.0, shadow_attenuation, albedo, roughness, metallic, specular, directional_lights.data[i].specular * specular_blob_intensity, + light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].size, directional_lights.data[i].color * directional_lights.data[i].energy, 1.0, shadow_attenuation, albedo, roughness, metallic, specular, directional_lights.data[i].specular * specular_blob_intensity, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif 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 e3f1e650ed..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,7 +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 directional_penumbra_shadow_samples; + uint directional_soft_shadow_samples; + uint penumbra_shadow_samples; + uint soft_shadow_samples; vec4 ambient_light_color_energy; @@ -141,17 +148,20 @@ struct LightData { //this structure needs to be as packed as possible vec3 position; float inv_radius; vec3 direction; + float size; uint attenuation_energy; //attenuation uint color_specular; //rgb color, a specular (8 bit unorm) uint cone_attenuation_angle; // attenuation and angle, (16bit float) - uint mask; uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm) vec4 atlas_rect; // used for spot mat4 shadow_matrix; float shadow_bias; float shadow_normal_bias; float transmittance_bias; - uint pad; + 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[2]; }; layout(set = 0, binding = 5, std430) buffer Lights { @@ -180,11 +190,11 @@ struct DirectionalLightData { vec3 direction; float energy; vec3 color; + float size; float specular; uint mask; - uint pad0; - uint pad1; - uint pad2; + float softshadow_angle; + float soft_shadow_scale; bool blend_splits; bool shadow_enabled; float fade_from; @@ -193,6 +203,7 @@ struct DirectionalLightData { vec4 shadow_normal_bias; vec4 shadow_transmittance_bias; vec4 shadow_transmittance_z_scale; + vec4 shadow_range_begin; vec4 shadow_split_offsets; mat4 shadow_matrix1; mat4 shadow_matrix2; @@ -202,6 +213,10 @@ struct DirectionalLightData { vec4 shadow_color2; vec4 shadow_color3; vec4 shadow_color4; + vec2 uv_scale1; + vec2 uv_scale2; + vec2 uv_scale3; + vec2 uv_scale4; }; layout(set = 0, binding = 7, std140) uniform DirectionalLights { 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_scene.cpp b/servers/rendering/rendering_server_scene.cpp index 4f40012c98..d66708587a 100644 --- a/servers/rendering/rendering_server_scene.cpp +++ b/servers/rendering/rendering_server_scene.cpp @@ -1499,7 +1499,9 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c if (j == 0 || d_z > z_max) z_max = d_z; } + real_t radius = 0; + real_t soft_shadow_expand = 0; Vector3 center; { @@ -1528,12 +1530,30 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c bias_scale = radius / first_radius; } - x_max_cam = x_vec.dot(center) + radius; - x_min_cam = x_vec.dot(center) - radius; - y_max_cam = y_vec.dot(center) + radius; - y_min_cam = y_vec.dot(center) - radius; z_min_cam = z_vec.dot(center) - radius; + { + + float soft_shadow_angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SIZE); + + if (soft_shadow_angle > 0.0 && pancake_size > 0.0) { + + float z_range = (z_vec.dot(center) + radius + pancake_size) - z_min_cam; + soft_shadow_expand = Math::tan(Math::deg2rad(soft_shadow_angle)) * z_range; + + x_max += soft_shadow_expand; + y_max += soft_shadow_expand; + + x_min -= soft_shadow_expand; + y_min -= soft_shadow_expand; + } + } + + x_max_cam = x_vec.dot(center) + radius + soft_shadow_expand; + x_min_cam = x_vec.dot(center) - radius - soft_shadow_expand; + y_max_cam = y_vec.dot(center) + radius + soft_shadow_expand; + y_min_cam = y_vec.dot(center) - radius - soft_shadow_expand; + if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) { //this trick here is what stabilizes the shadow (make potential jaggies to not move) //at the cost of some wasted resolution. Still the quality increase is very well worth it @@ -1588,8 +1608,9 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c } } - if (cull_max > z_max) + if (cull_max > z_max) { z_max = cull_max; + } if (pancake_size > 0) { z_max = z_vec.dot(center) + radius + pancake_size; @@ -1677,11 +1698,19 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c ortho_camera.set_orthogonal(-half_x, half_x, -half_y, half_y, 0, (z_max - z_min_cam)); + Vector2 uv_scale(1.0 / (x_max_cam - x_min_cam), 1.0 / (y_max_cam - y_min_cam)); + Transform ortho_transform; ortho_transform.basis = transform.basis; ortho_transform.origin = x_vec * (x_min_cam + half_x) + y_vec * (y_min_cam + half_y) + z_vec * z_max; - RSG::scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, z_max - z_min_cam, distances[i + 1], i, radius * 2.0 / texture_size, bias_scale * aspect_bias_scale * min_distance_bias_scale); + { + Vector3 max_in_view = p_cam_transform.affine_inverse().xform(z_vec * cull_max); + Vector3 dir_in_view = p_cam_transform.xform_inv(z_vec).normalized(); + cull_max = dir_in_view.dot(max_in_view); + } + + RSG::scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, z_max - z_min_cam, distances[i + 1], i, radius * 2.0 / texture_size, bias_scale * aspect_bias_scale * min_distance_bias_scale, z_max, uv_scale); } RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); 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.cpp b/servers/rendering/rendering_server_wrap_mt.cpp index aa3bf583c7..4ca13dbef9 100644 --- a/servers/rendering/rendering_server_wrap_mt.cpp +++ b/servers/rendering/rendering_server_wrap_mt.cpp @@ -126,17 +126,6 @@ void RenderingServerWrapMT::init() { void RenderingServerWrapMT::finish() { - if (thread) { - - command_queue.push(this, &RenderingServerWrapMT::thread_exit); - Thread::wait_to_finish(thread); - memdelete(thread); - - thread = nullptr; - } else { - rendering_server->finish(); - } - sky_free_cached_ids(); shader_free_cached_ids(); material_free_cached_ids(); @@ -161,6 +150,17 @@ void RenderingServerWrapMT::finish() { canvas_item_free_cached_ids(); canvas_light_occluder_free_cached_ids(); canvas_occluder_polygon_free_cached_ids(); + + if (thread) { + + command_queue.push(this, &RenderingServerWrapMT::thread_exit); + Thread::wait_to_finish(thread); + memdelete(thread); + + thread = nullptr; + } else { + rendering_server->finish(); + } } void RenderingServerWrapMT::set_use_vsync_callback(bool p_enable) { 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 cb7c2cecf6..a31c9f39fd 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -382,6 +382,7 @@ public: LIGHT_PARAM_INDIRECT_ENERGY, LIGHT_PARAM_SPECULAR, LIGHT_PARAM_RANGE, + LIGHT_PARAM_SIZE, LIGHT_PARAM_ATTENUATION, LIGHT_PARAM_SPOT_ANGLE, LIGHT_PARAM_SPOT_ATTENUATION, @@ -393,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 }; @@ -632,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, @@ -672,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 */ @@ -817,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 */ diff --git a/thirdparty/vulkan/android/vk_mem_alloc.cpp b/thirdparty/vulkan/android/vk_mem_alloc.cpp new file mode 100644 index 0000000000..a28454cf6e --- /dev/null +++ b/thirdparty/vulkan/android/vk_mem_alloc.cpp @@ -0,0 +1,8 @@ +#define VMA_IMPLEMENTATION +#ifdef DEBUG_ENABLED +#ifndef _DEBUG +#define _DEBUG +#endif +#endif +// Include memory allocator from Android NDK +#include <vk_mem_alloc.h> |