summaryrefslogtreecommitdiff
path: root/servers/rendering
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering')
-rw-r--r--servers/rendering/rasterizer_dummy.h795
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp602
-rw-r--r--servers/rendering/renderer_canvas_cull.h43
-rw-r--r--servers/rendering/renderer_canvas_render.h20
-rw-r--r--servers/rendering/renderer_compositor.cpp9
-rw-r--r--servers/rendering/renderer_compositor.h54
-rw-r--r--servers/rendering/renderer_rd/cluster_builder_rd.cpp10
-rw-r--r--servers/rendering/renderer_rd/cluster_builder_rd.h16
-rw-r--r--servers/rendering/renderer_rd/effects_rd.cpp1045
-rw-r--r--servers/rendering/renderer_rd/effects_rd.h250
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp613
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h177
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp327
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h51
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp879
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h209
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp287
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h31
-rw-r--r--servers/rendering/renderer_rd/pipeline_cache_rd.cpp40
-rw-r--r--servers/rendering/renderer_rd/pipeline_cache_rd.h14
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp288
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h24
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp149
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h14
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp12
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_environment_rd.h12
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp381
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_gi_rd.h133
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp2335
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h654
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp657
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.h137
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp2826
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.h480
-rw-r--r--servers/rendering/renderer_rd/shader_compiler_rd.cpp361
-rw-r--r--servers/rendering/renderer_rd/shader_compiler_rd.h2
-rw-r--r--servers/rendering/renderer_rd/shader_rd.cpp264
-rw-r--r--servers/rendering/renderer_rd/shader_rd.h25
-rw-r--r--servers/rendering/renderer_rd/shaders/blit.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/blur_raster.glsl138
-rw-r--r--servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl21
-rw-r--r--servers/rendering/renderer_rd/shaders/bokeh_dof.glsl38
-rw-r--r--servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl37
-rw-r--r--servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl253
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl110
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_sdf.glsl60
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_render.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/cube_to_dp.glsl14
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl48
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl48
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl163
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl256
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl95
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl94
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl63
-rw-r--r--servers/rendering/renderer_rd/shaders/decal_data_inc.glsl28
-rw-r--r--servers/rendering/renderer_rd/shaders/fsr_upscale.glsl173
-rw-r--r--servers/rendering/renderer_rd/shaders/gi.glsl97
-rw-r--r--servers/rendering/renderer_rd/shaders/giprobe_write.glsl47
-rw-r--r--servers/rendering/renderer_rd/shaders/light_data_inc.glsl104
-rw-r--r--servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl74
-rw-r--r--servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl11
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl238
-rw-r--r--servers/rendering/renderer_rd/shaders/particles_copy.glsl49
-rw-r--r--servers/rendering/renderer_rd/shaders/resolve.glsl38
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl5
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl921
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl62
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl32
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl463
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl239
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl134
-rw-r--r--servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl15
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/sky.glsl46
-rw-r--r--servers/rendering/renderer_rd/shaders/tonemap.glsl133
-rw-r--r--servers/rendering/renderer_rd/shaders/volumetric_fog.glsl755
-rw-r--r--servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl776
-rw-r--r--servers/rendering/renderer_rd/shaders/voxel_gi.glsl (renamed from servers/rendering/renderer_rd/shaders/giprobe.glsl)162
-rw-r--r--servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl (renamed from servers/rendering/renderer_rd/shaders/giprobe_debug.glsl)5
-rw-r--r--servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl (renamed from servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl)0
-rw-r--r--servers/rendering/renderer_scene.h36
-rw-r--r--servers/rendering/renderer_scene_cull.cpp1587
-rw-r--r--servers/rendering/renderer_scene_cull.h218
-rw-r--r--servers/rendering/renderer_scene_occlusion_cull.cpp4
-rw-r--r--servers/rendering/renderer_scene_occlusion_cull.h30
-rw-r--r--servers/rendering/renderer_scene_render.cpp150
-rw-r--r--servers/rendering/renderer_scene_render.h71
-rw-r--r--servers/rendering/renderer_storage.cpp20
-rw-r--r--servers/rendering/renderer_storage.h164
-rw-r--r--servers/rendering/renderer_viewport.cpp472
-rw-r--r--servers/rendering/renderer_viewport.h60
-rw-r--r--servers/rendering/rendering_device.cpp224
-rw-r--r--servers/rendering/rendering_device.h135
-rw-r--r--servers/rendering/rendering_device_binds.cpp14
-rw-r--r--servers/rendering/rendering_device_binds.h169
-rw-r--r--servers/rendering/rendering_server_default.cpp92
-rw-r--r--servers/rendering/rendering_server_default.h193
-rw-r--r--servers/rendering/rendering_server_globals.cpp2
-rw-r--r--servers/rendering/rendering_server_globals.h2
-rw-r--r--servers/rendering/shader_language.cpp4404
-rw-r--r--servers/rendering/shader_language.h153
-rw-r--r--servers/rendering/shader_types.cpp75
-rw-r--r--servers/rendering/shader_types.h8
-rw-r--r--servers/rendering/shader_warnings.cpp135
-rw-r--r--servers/rendering/shader_warnings.h85
110 files changed, 19656 insertions, 9148 deletions
diff --git a/servers/rendering/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h
new file mode 100644
index 0000000000..3451ea2d39
--- /dev/null
+++ b/servers/rendering/rasterizer_dummy.h
@@ -0,0 +1,795 @@
+/*************************************************************************/
+/* rasterizer_dummy.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 RASTERIZER_DUMMY_H
+#define RASTERIZER_DUMMY_H
+
+#include "core/math/camera_matrix.h"
+#include "core/templates/rid_owner.h"
+#include "core/templates/self_list.h"
+#include "scene/resources/mesh.h"
+#include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/renderer_scene_render.h"
+#include "servers/rendering_server.h"
+
+class RasterizerSceneDummy : public RendererSceneRender {
+public:
+ GeometryInstance *geometry_instance_create(RID p_base) override { return nullptr; }
+ void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override {}
+ void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override {}
+ void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) override {}
+ void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override {}
+ void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) override {}
+ void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) override {}
+ void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) override {}
+ void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) override {}
+ void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) override {}
+ void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override {}
+ void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) override {}
+ void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) override {}
+ void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) override {}
+ void geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) override {}
+ void geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) override {}
+ void geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) override {}
+
+ uint32_t geometry_instance_get_pair_mask() override { return 0; }
+ void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) override {}
+ void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {}
+ void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) override {}
+ void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override {}
+ void geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) override {}
+
+ void geometry_instance_free(GeometryInstance *p_geometry_instance) override {}
+
+ /* SHADOW ATLAS API */
+
+ RID shadow_atlas_create() override { return RID(); }
+ void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false) override {}
+ void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override {}
+ bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override { return false; }
+
+ void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) override {}
+ int get_directional_light_shadow_size(RID p_light_intance) override { return 0; }
+ void set_directional_shadow_count(int p_count) override {}
+
+ /* SDFGI UPDATE */
+
+ void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}
+ int sdfgi_get_pending_region_count(RID p_render_buffers) const override { return 0; }
+ AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const override { return AABB(); }
+ uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const override { return 0; }
+
+ /* SKY API */
+
+ RID sky_allocate() override { return RID(); }
+ void sky_initialize(RID p_rid) override {}
+ void sky_set_radiance_size(RID p_sky, int p_radiance_size) override {}
+ void sky_set_mode(RID p_sky, RS::SkyMode p_samples) override {}
+ void sky_set_material(RID p_sky, RID p_material) override {}
+ Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) override { return Ref<Image>(); }
+
+ /* ENVIRONMENT API */
+
+ RID environment_allocate() override { return RID(); }
+ void environment_initialize(RID p_rid) override {}
+ void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) override {}
+ void environment_set_sky(RID p_env, RID p_sky) override {}
+ void environment_set_sky_custom_fov(RID p_env, float p_scale) override {}
+ void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) override {}
+ void environment_set_bg_color(RID p_env, const Color &p_color) override {}
+ void environment_set_bg_energy(RID p_env, float p_energy) override {}
+ void environment_set_canvas_max_layer(RID p_env, int p_max_layer) override {}
+ void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) override {}
+
+ void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) override {}
+ void environment_glow_set_use_bicubic_upscale(bool p_enable) override {}
+ void environment_glow_set_use_high_quality(bool p_enable) override {}
+
+ void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) override {}
+ void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override {}
+ void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) override {}
+ void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {}
+
+ void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) override {}
+
+ void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) override {}
+ void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) override {}
+ void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) override {}
+
+ void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) override {}
+
+ void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) override {}
+
+ void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) override {}
+ void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) override {}
+ void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) override {}
+ void environment_set_volumetric_fog_filter_active(bool p_enable) override {}
+
+ Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override { return Ref<Image>(); }
+
+ bool is_environment(RID p_env) const override { return false; }
+ RS::EnvironmentBG environment_get_background(RID p_env) const override { return RS::ENV_BG_KEEP; }
+ int environment_get_canvas_max_layer(RID p_env) const override { return 0; }
+
+ RID camera_effects_allocate() override { return RID(); }
+ void camera_effects_initialize(RID p_rid) override {}
+ void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) override {}
+ void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) override {}
+
+ 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) override {}
+ void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) override {}
+
+ void shadows_quality_set(RS::ShadowQuality p_quality) override {}
+ void directional_shadow_quality_set(RS::ShadowQuality p_quality) override {}
+
+ RID light_instance_create(RID p_light) override { return RID(); }
+ void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override {}
+ void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override {}
+ void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &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()) override {}
+ void light_instance_mark_visible(RID p_light_instance) override {}
+
+ RID fog_volume_instance_create(RID p_fog_volume) override { return RID(); }
+ void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override {}
+ void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override {}
+ RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override { return RID(); }
+ Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override { return Vector3(); }
+
+ RID reflection_atlas_create() override { return RID(); }
+ int reflection_atlas_get_size(RID p_ref_atlas) const override { return 0; }
+ void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override {}
+
+ RID reflection_probe_instance_create(RID p_probe) override { return RID(); }
+ void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override {}
+ void reflection_probe_release_atlas_index(RID p_instance) override {}
+ bool reflection_probe_instance_needs_redraw(RID p_instance) override { return false; }
+ bool reflection_probe_instance_has_reflection(RID p_instance) override { return false; }
+ bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override { return false; }
+ bool reflection_probe_instance_postprocess_step(RID p_instance) override { return true; }
+
+ RID decal_instance_create(RID p_decal) override { return RID(); }
+ void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {}
+
+ RID lightmap_instance_create(RID p_lightmap) override { return RID(); }
+ void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override {}
+
+ RID voxel_gi_instance_create(RID p_voxel_gi) override { return RID(); }
+ void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) override {}
+ bool voxel_gi_needs_update(RID p_probe) const override { return false; }
+ void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects) override {}
+
+ void voxel_gi_set_quality(RS::VoxelGIQuality) override {}
+
+ void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_info = nullptr) override {}
+ void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override {}
+ void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) override {}
+
+ void set_scene_pass(uint64_t p_pass) override {}
+ void set_time(double p_time, double p_step) override {}
+ void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override {}
+
+ RID render_buffers_create() override { return RID(); }
+ void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override {}
+ void gi_set_use_half_resolution(bool p_enable) override {}
+
+ void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override {}
+ bool screen_space_roughness_limiter_is_active() const override { return false; }
+
+ void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override {}
+ void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override {}
+
+ TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) override { return TypedArray<Image>(); }
+
+ bool free(RID p_rid) override { return false; }
+ void update() override {}
+ void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override {}
+
+ virtual void decals_set_filter(RS::DecalFilter p_filter) override {}
+ virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) override {}
+
+ RasterizerSceneDummy() {}
+ ~RasterizerSceneDummy() {}
+};
+
+class RasterizerStorageDummy : public RendererStorage {
+public:
+ bool can_create_resources_async() const override { return false; }
+
+ /* TEXTURE API */
+ struct DummyTexture {
+ Ref<Image> image;
+ };
+ mutable RID_PtrOwner<DummyTexture> texture_owner;
+
+ RID texture_allocate() override {
+ DummyTexture *texture = memnew(DummyTexture);
+ ERR_FAIL_COND_V(!texture, RID());
+ return texture_owner.make_rid(texture);
+ }
+ void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) override {
+ DummyTexture *t = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND(!t);
+ t->image = p_image->duplicate();
+ }
+
+ void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override {}
+ void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override {}
+ void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override {}
+ void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override {}
+ void texture_proxy_initialize(RID p_texture, RID p_base) override {}
+ void texture_proxy_update(RID p_proxy, RID p_base) override {}
+
+ void texture_2d_placeholder_initialize(RID p_texture) override {}
+ void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) override {}
+ void texture_3d_placeholder_initialize(RID p_texture) override {}
+
+ Ref<Image> texture_2d_get(RID p_texture) const override {
+ DummyTexture *t = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND_V(!t, Ref<Image>());
+ return t->image;
+ }
+
+ Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const override { return Ref<Image>(); }
+ Vector<Ref<Image>> texture_3d_get(RID p_texture) const override { return Vector<Ref<Image>>(); }
+
+ void texture_replace(RID p_texture, RID p_by_texture) override { free(p_by_texture); }
+ void texture_set_size_override(RID p_texture, int p_width, int p_height) override {}
+
+ void texture_set_path(RID p_texture, const String &p_path) override {}
+ String texture_get_path(RID p_texture) const override { return String(); }
+
+ void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override {}
+ void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override {}
+ void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) override {}
+
+ void texture_debug_usage(List<RS::TextureInfo> *r_info) override {}
+ void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) override {}
+ Size2 texture_size_with_proxy(RID p_proxy) override { return Size2(); }
+
+ void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
+ void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
+
+ /* CANVAS TEXTURE API */
+
+ RID canvas_texture_allocate() override { return RID(); }
+ void canvas_texture_initialize(RID p_rid) override {}
+ void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) override {}
+ void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) override {}
+
+ void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override {}
+ void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override {}
+
+ /* SHADER API */
+
+ RID shader_allocate() override { return RID(); }
+ void shader_initialize(RID p_rid) override {}
+ void shader_set_code(RID p_shader, const String &p_code) override {}
+ String shader_get_code(RID p_shader) const override { return ""; }
+ void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const override {}
+
+ void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override {}
+ RID shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const override { return RID(); }
+ Variant shader_get_param_default(RID p_material, const StringName &p_param) const override { return Variant(); }
+
+ RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override { return RS::ShaderNativeSourceCode(); };
+
+ /* COMMON MATERIAL API */
+
+ RID material_allocate() override { return RID(); }
+ void material_initialize(RID p_rid) override {}
+ void material_set_render_priority(RID p_material, int priority) override {}
+ void material_set_shader(RID p_shader_material, RID p_shader) override {}
+
+ void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) override {}
+ Variant material_get_param(RID p_material, const StringName &p_param) const override { return Variant(); }
+
+ void material_set_next_pass(RID p_material, RID p_next_material) override {}
+
+ bool material_is_animated(RID p_material) override { return false; }
+ bool material_casts_shadows(RID p_material) override { return false; }
+ void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) override {}
+ void material_update_dependency(RID p_material, DependencyTracker *p_instance) override {}
+
+ /* MESH API */
+
+ RID mesh_allocate() override { return RID(); }
+ void mesh_initialize(RID p_rid) override {}
+ void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override {}
+ bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override { return false; }
+ RID mesh_instance_create(RID p_base) override { return RID(); }
+ void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override {}
+ void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override {}
+ void mesh_instance_check_for_update(RID p_mesh_instance) override {}
+ void update_mesh_instances() override {}
+ void reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) override {}
+ float reflection_probe_get_lod_threshold(RID p_probe) const override { return 0.0; }
+
+ void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override {}
+
+ int mesh_get_blend_shape_count(RID p_mesh) const override { return 0; }
+
+ void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override {}
+ RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override { return RS::BLEND_SHAPE_MODE_NORMALIZED; }
+
+ void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
+ void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
+ void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
+
+ void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override {}
+ RID mesh_surface_get_material(RID p_mesh, int p_surface) const override { return RID(); }
+
+ RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override { return RS::SurfaceData(); }
+ int mesh_get_surface_count(RID p_mesh) const override { return 0; }
+
+ void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override {}
+ AABB mesh_get_custom_aabb(RID p_mesh) const override { return AABB(); }
+
+ AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override { return AABB(); }
+ void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override {}
+ void mesh_clear(RID p_mesh) override {}
+
+ /* MULTIMESH API */
+
+ RID multimesh_allocate() override { return RID(); }
+ void multimesh_initialize(RID p_rid) override {}
+ void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override {}
+ int multimesh_get_instance_count(RID p_multimesh) const override { return 0; }
+
+ void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override {}
+ void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override {}
+ void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override {}
+ void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override {}
+ void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override {}
+
+ RID multimesh_get_mesh(RID p_multimesh) const override { return RID(); }
+ AABB multimesh_get_aabb(RID p_multimesh) const override { return AABB(); }
+
+ Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override { return Transform3D(); }
+ Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override { return Transform2D(); }
+ Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override { return Color(); }
+ Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override { return Color(); }
+ void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override {}
+ Vector<float> multimesh_get_buffer(RID p_multimesh) const override { return Vector<float>(); }
+
+ void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override {}
+ int multimesh_get_visible_instances(RID p_multimesh) const override { return 0; }
+
+ /* SKELETON API */
+
+ RID skeleton_allocate() override { return RID(); }
+ void skeleton_initialize(RID p_rid) override {}
+ void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override {}
+ void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override {}
+ int skeleton_get_bone_count(RID p_skeleton) const override { return 0; }
+ void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) override {}
+ Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override { return Transform3D(); }
+ void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) override {}
+ Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const override { return Transform2D(); }
+
+ /* Light API */
+
+ RID directional_light_allocate() override { return RID(); }
+ void directional_light_initialize(RID p_rid) override {}
+ RID omni_light_allocate() override { return RID(); }
+ void omni_light_initialize(RID p_rid) override {}
+ RID spot_light_allocate() override { return RID(); }
+ void spot_light_initialize(RID p_rid) override {}
+ RID reflection_probe_allocate() override { return RID(); }
+ void reflection_probe_initialize(RID p_rid) override {}
+
+ void light_set_color(RID p_light, const Color &p_color) override {}
+ void light_set_param(RID p_light, RS::LightParam p_param, float p_value) override {}
+ void light_set_shadow(RID p_light, bool p_enabled) override {}
+ void light_set_shadow_color(RID p_light, const Color &p_color) override {}
+ void light_set_projector(RID p_light, RID p_texture) override {}
+ void light_set_negative(RID p_light, bool p_enable) override {}
+ void light_set_cull_mask(RID p_light, uint32_t p_mask) override {}
+ void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override {}
+ void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override {}
+ void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override {}
+
+ void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) override {}
+
+ void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) override {}
+ void light_directional_set_blend_splits(RID p_light, bool p_enable) override {}
+ bool light_directional_get_blend_splits(RID p_light) const override { return false; }
+ void light_directional_set_sky_only(RID p_light, bool p_sky_only) override {}
+ bool light_directional_is_sky_only(RID p_light) const override { return false; }
+
+ RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) override { return RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; }
+ RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) override { return RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; }
+
+ bool light_has_shadow(RID p_light) const override { return false; }
+ bool light_has_projector(RID p_light) const override { return false; }
+
+ RS::LightType light_get_type(RID p_light) const override { return RS::LIGHT_OMNI; }
+ AABB light_get_aabb(RID p_light) const override { return AABB(); }
+ float light_get_param(RID p_light, RS::LightParam p_param) override { return 0.0; }
+ Color light_get_color(RID p_light) override { return Color(); }
+ RS::LightBakeMode light_get_bake_mode(RID p_light) override { return RS::LIGHT_BAKE_DISABLED; }
+ uint32_t light_get_max_sdfgi_cascade(RID p_light) override { return 0; }
+ uint64_t light_get_version(RID p_light) const override { return 0; }
+
+ /* PROBE API */
+
+ void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) override {}
+ void reflection_probe_set_intensity(RID p_probe, float p_intensity) override {}
+ void reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) override {}
+ void reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) override {}
+ void reflection_probe_set_ambient_energy(RID p_probe, float p_energy) override {}
+ void reflection_probe_set_max_distance(RID p_probe, float p_distance) override {}
+ void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) override {}
+ void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) override {}
+ void reflection_probe_set_as_interior(RID p_probe, bool p_enable) override {}
+ void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) override {}
+ void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) override {}
+ void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) override {}
+ void reflection_probe_set_resolution(RID p_probe, int p_resolution) override {}
+
+ AABB reflection_probe_get_aabb(RID p_probe) const override { return AABB(); }
+ RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const override { return RenderingServer::REFLECTION_PROBE_UPDATE_ONCE; }
+ uint32_t reflection_probe_get_cull_mask(RID p_probe) const override { return 0; }
+ Vector3 reflection_probe_get_extents(RID p_probe) const override { return Vector3(); }
+ Vector3 reflection_probe_get_origin_offset(RID p_probe) const override { return Vector3(); }
+ float reflection_probe_get_origin_max_distance(RID p_probe) const override { return 0.0; }
+ bool reflection_probe_renders_shadows(RID p_probe) const override { return false; }
+
+ void base_update_dependency(RID p_base, DependencyTracker *p_instance) override {}
+ void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) override {}
+
+ /* DECAL API */
+
+ RID decal_allocate() override { return RID(); }
+ void decal_initialize(RID p_rid) override {}
+ void decal_set_extents(RID p_decal, const Vector3 &p_extents) override {}
+ void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) override {}
+ void decal_set_emission_energy(RID p_decal, float p_energy) override {}
+ void decal_set_albedo_mix(RID p_decal, float p_mix) override {}
+ void decal_set_modulate(RID p_decal, const Color &p_modulate) override {}
+ void decal_set_cull_mask(RID p_decal, uint32_t p_layers) override {}
+ void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) override {}
+ void decal_set_fade(RID p_decal, float p_above, float p_below) override {}
+ void decal_set_normal_fade(RID p_decal, float p_fade) override {}
+
+ AABB decal_get_aabb(RID p_decal) const override { return AABB(); }
+
+ /* VOXEL GI API */
+
+ RID voxel_gi_allocate() override { return RID(); }
+ void voxel_gi_initialize(RID p_rid) override {}
+ void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) override {}
+
+ AABB voxel_gi_get_bounds(RID p_voxel_gi) const override { return AABB(); }
+ Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const override { return Vector3i(); }
+ Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const override { return Vector<uint8_t>(); }
+ Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const override { return Vector<uint8_t>(); }
+ Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const override { return Vector<uint8_t>(); }
+
+ Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const override { return Vector<int>(); }
+ Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const override { return Transform3D(); }
+
+ void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) override {}
+ float voxel_gi_get_dynamic_range(RID p_voxel_gi) const override { return 0; }
+
+ void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) override {}
+ float voxel_gi_get_propagation(RID p_voxel_gi) const override { return 0; }
+
+ void voxel_gi_set_energy(RID p_voxel_gi, float p_range) override {}
+ float voxel_gi_get_energy(RID p_voxel_gi) const override { return 0.0; }
+
+ void voxel_gi_set_bias(RID p_voxel_gi, float p_range) override {}
+ float voxel_gi_get_bias(RID p_voxel_gi) const override { return 0.0; }
+
+ void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) override {}
+ float voxel_gi_get_normal_bias(RID p_voxel_gi) const override { return 0.0; }
+
+ void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) override {}
+ bool voxel_gi_is_interior(RID p_voxel_gi) const override { return false; }
+
+ void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) override {}
+ bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const override { return false; }
+
+ void voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) override {}
+ float voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const override { return 0; }
+
+ uint32_t voxel_gi_get_version(RID p_voxel_gi) override { return 0; }
+
+ /* LIGHTMAP CAPTURE */
+ RID lightmap_allocate() override { return RID(); }
+ void lightmap_initialize(RID p_rid) override {}
+ void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) override {}
+ void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) override {}
+ void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) override {}
+ void lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) override {}
+ PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const override { return PackedVector3Array(); }
+ PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const override { return PackedColorArray(); }
+ PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const override { return PackedInt32Array(); }
+ PackedInt32Array lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const override { return PackedInt32Array(); }
+ AABB lightmap_get_aabb(RID p_lightmap) const override { return AABB(); }
+ void lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) override {}
+ bool lightmap_is_interior(RID p_lightmap) const override { return false; }
+ void lightmap_set_probe_capture_update_speed(float p_speed) override {}
+ float lightmap_get_probe_capture_update_speed() const override { return 0; }
+
+ /* OCCLUDER */
+
+ void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) {}
+
+ /* PARTICLES */
+
+ RID particles_allocate() override { return RID(); }
+ void particles_initialize(RID p_rid) override {}
+ void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override {}
+ void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override {}
+ void particles_set_emitting(RID p_particles, bool p_emitting) override {}
+ void particles_set_amount(RID p_particles, int p_amount) override {}
+ void particles_set_lifetime(RID p_particles, double p_lifetime) override {}
+ void particles_set_one_shot(RID p_particles, bool p_one_shot) override {}
+ void particles_set_pre_process_time(RID p_particles, double p_time) override {}
+ void particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) override {}
+ void particles_set_randomness_ratio(RID p_particles, real_t p_ratio) override {}
+ void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) override {}
+ void particles_set_speed_scale(RID p_particles, double p_scale) override {}
+ void particles_set_use_local_coordinates(RID p_particles, bool p_enable) override {}
+ void particles_set_process_material(RID p_particles, RID p_material) override {}
+ void particles_set_fixed_fps(RID p_particles, int p_fps) override {}
+ void particles_set_interpolate(RID p_particles, bool p_enable) override {}
+ void particles_set_fractional_delta(RID p_particles, bool p_enable) override {}
+ void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) override {}
+ void particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) override {}
+ void particles_set_collision_base_size(RID p_particles, real_t p_size) override {}
+
+ void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) override {}
+
+ void particles_set_trails(RID p_particles, bool p_enable, double p_length) override {}
+ void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) override {}
+
+ void particles_restart(RID p_particles) override {}
+
+ void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) override {}
+
+ void particles_set_draw_passes(RID p_particles, int p_count) override {}
+ void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) override {}
+
+ void particles_request_process(RID p_particles) override {}
+ AABB particles_get_current_aabb(RID p_particles) override { return AABB(); }
+ AABB particles_get_aabb(RID p_particles) const override { return AABB(); }
+
+ void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override {}
+
+ bool particles_get_emitting(RID p_particles) override { return false; }
+ int particles_get_draw_passes(RID p_particles) const override { return 0; }
+ RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const override { return RID(); }
+
+ void particles_add_collision(RID p_particles, RID p_instance) override {}
+ void particles_remove_collision(RID p_particles, RID p_instance) override {}
+
+ void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) override {}
+
+ void update_particles() override {}
+
+ /* PARTICLES COLLISION */
+
+ RID particles_collision_allocate() override { return RID(); }
+ void particles_collision_initialize(RID p_rid) override {}
+ void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) override {}
+ void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) override {}
+ void particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) override {}
+ void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) override {}
+ void particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) override {}
+ void particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) override {}
+ void particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) override {}
+ void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) override {}
+ void particles_collision_height_field_update(RID p_particles_collision) override {}
+ void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) override {}
+ AABB particles_collision_get_aabb(RID p_particles_collision) const override { return AABB(); }
+ bool particles_collision_is_heightfield(RID p_particles_collision) const override { return false; }
+ RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const override { return RID(); }
+
+ RID particles_collision_instance_create(RID p_collision) override { return RID(); }
+ void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) override {}
+ void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override {}
+
+ /* FOG VOLUMES */
+
+ RID fog_volume_allocate() override { return RID(); }
+ void fog_volume_initialize(RID p_rid) override {}
+
+ void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override {}
+ void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override {}
+ void fog_volume_set_material(RID p_fog_volume, RID p_material) override {}
+ AABB fog_volume_get_aabb(RID p_fog_volume) const override { return AABB(); }
+ RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const override { return RS::FOG_VOLUME_SHAPE_BOX; }
+
+ /* VISIBILITY NOTIFIER */
+ virtual RID visibility_notifier_allocate() override { return RID(); }
+ virtual void visibility_notifier_initialize(RID p_notifier) override {}
+ virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) override {}
+ virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) override {}
+
+ virtual AABB visibility_notifier_get_aabb(RID p_notifier) const override { return AABB(); }
+ virtual void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) override {}
+
+ /* GLOBAL VARIABLES */
+
+ void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) override {}
+ void global_variable_remove(const StringName &p_name) override {}
+ Vector<StringName> global_variable_get_list() const override { return Vector<StringName>(); }
+
+ void global_variable_set(const StringName &p_name, const Variant &p_value) override {}
+ void global_variable_set_override(const StringName &p_name, const Variant &p_value) override {}
+ Variant global_variable_get(const StringName &p_name) const override { return Variant(); }
+ RS::GlobalVariableType global_variable_get_type(const StringName &p_name) const override { return RS::GLOBAL_VAR_TYPE_MAX; }
+
+ void global_variables_load_settings(bool p_load_textures = true) override {}
+ void global_variables_clear() override {}
+
+ int32_t global_variables_instance_allocate(RID p_instance) override { return 0; }
+ void global_variables_instance_free(RID p_instance) override {}
+ void global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) override {}
+
+ bool particles_is_inactive(RID p_particles) const override { return false; }
+
+ /* RENDER TARGET */
+
+ RID render_target_create() override { return RID(); }
+ void render_target_set_position(RID p_render_target, int p_x, int p_y) override {}
+ void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override {}
+ RID render_target_get_texture(RID p_render_target) override { return RID(); }
+ void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override {}
+ void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) override {}
+ bool render_target_was_used(RID p_render_target) override { return false; }
+ void render_target_set_as_unused(RID p_render_target) override {}
+
+ void render_target_request_clear(RID p_render_target, const Color &p_clear_color) override {}
+ bool render_target_is_clear_requested(RID p_render_target) override { return false; }
+ Color render_target_get_clear_request_color(RID p_render_target) override { return Color(); }
+ void render_target_disable_clear_request(RID p_render_target) override {}
+ void render_target_do_clear_request(RID p_render_target) override {}
+
+ void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override {}
+ Rect2i render_target_get_sdf_rect(RID p_render_target) const override { return Rect2i(); }
+ void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override {}
+
+ RS::InstanceType get_base_type(RID p_rid) const override { return RS::INSTANCE_NONE; }
+ bool free(RID p_rid) override {
+ if (texture_owner.owns(p_rid)) {
+ // delete the texture
+ DummyTexture *texture = texture_owner.get_or_null(p_rid);
+ texture_owner.free(p_rid);
+ memdelete(texture);
+ return true;
+ }
+ return false;
+ }
+
+ virtual void update_memory_info() override {}
+ virtual uint64_t get_rendering_info(RS::RenderingInfo p_info) override { return 0; }
+
+ bool has_os_feature(const String &p_feature) const override { return false; }
+
+ void update_dirty_resources() override {}
+
+ void set_debug_generate_wireframes(bool p_generate) override {}
+
+ String get_video_adapter_name() const override { return String(); }
+ String get_video_adapter_vendor() const override { return String(); }
+
+ static RendererStorage *base_singleton;
+
+ void capture_timestamps_begin() override {}
+ void capture_timestamp(const String &p_name) override {}
+ uint32_t get_captured_timestamps_count() const override { return 0; }
+ uint64_t get_captured_timestamps_frame() const override { return 0; }
+ uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const override { return 0; }
+ uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const override { return 0; }
+ String get_captured_timestamp_name(uint32_t p_index) const override { return String(); }
+
+ RasterizerStorageDummy() {}
+ ~RasterizerStorageDummy() {}
+};
+
+class RasterizerCanvasDummy : public RendererCanvasRender {
+public:
+ PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) override { return 0; }
+ void free_polygon(PolygonID p_polygon) override {}
+
+ void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) override {}
+ void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) override {}
+
+ RID light_create() override { return RID(); }
+ void light_set_texture(RID p_rid, RID p_texture) override {}
+ void light_set_use_shadow(RID p_rid, bool p_enable) override {}
+ void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) override {}
+ void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) override {}
+
+ void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) override {}
+ RID occluder_polygon_create() override { return RID(); }
+ void occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) override {}
+ void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) override {}
+ void set_shadow_texture_size(int p_size) override {}
+
+ bool free(RID p_rid) override { return true; }
+ void update() override {}
+
+ RasterizerCanvasDummy() {}
+ ~RasterizerCanvasDummy() {}
+};
+
+class RasterizerDummy : public RendererCompositor {
+private:
+ uint64_t frame = 1;
+ double delta = 0;
+
+protected:
+ RasterizerCanvasDummy canvas;
+ RasterizerStorageDummy storage;
+ RasterizerSceneDummy scene;
+
+public:
+ RendererStorage *get_storage() override { return &storage; }
+ RendererCanvasRender *get_canvas() override { return &canvas; }
+ RendererSceneRender *get_scene() override { return &scene; }
+
+ void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) override {}
+
+ void initialize() override {}
+ void begin_frame(double frame_step) override {
+ frame++;
+ delta = frame_step;
+ }
+
+ void prepare_for_blitting_render_targets() override {}
+ void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) override {}
+
+ void end_frame(bool p_swap_buffers) override {
+ if (p_swap_buffers) {
+ DisplayServer::get_singleton()->swap_buffers();
+ }
+ }
+
+ void finalize() override {}
+
+ static RendererCompositor *_create_current() {
+ return memnew(RasterizerDummy);
+ }
+
+ static void make_current() {
+ _create_func = _create_current;
+ }
+
+ bool is_low_end() const override { return true; }
+ uint64_t get_frame_number() const override { return frame; }
+ double get_frame_delta_time() const override { return delta; }
+
+ RasterizerDummy() {}
+ ~RasterizerDummy() {}
+};
+
+#endif // RASTERIZER_DUMMY_H
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index 67003a6f64..7b70483571 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -44,10 +44,10 @@ void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas
memset(z_last_list, 0, z_range * sizeof(RendererCanvasRender::Item *));
for (int i = 0; i < p_child_item_count; i++) {
- _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr);
+ _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true);
}
if (p_canvas_item) {
- _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr);
+ _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true);
}
RendererCanvasRender::Item *list = nullptr;
@@ -97,105 +97,14 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2
}
}
-void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_PtrOwner<RendererCanvasCull::Item, true> &canvas_item_owner) {
+void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_Owner<RendererCanvasCull::Item, true> &canvas_item_owner) {
do {
ysort_owner->ysort_children_count = -1;
- ysort_owner = canvas_item_owner.owns(ysort_owner->parent) ? canvas_item_owner.getornull(ysort_owner->parent) : nullptr;
+ ysort_owner = canvas_item_owner.owns(ysort_owner->parent) ? canvas_item_owner.get_or_null(ysort_owner->parent) : nullptr;
} while (ysort_owner && ysort_owner->sort_y);
}
-void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner) {
- Item *ci = p_canvas_item;
-
- if (!ci->visible) {
- return;
- }
-
- if (ci->children_order_dirty) {
- ci->child_items.sort_custom<ItemIndexSort>();
- ci->children_order_dirty = false;
- }
-
- Rect2 rect = ci->get_rect();
- Transform2D xform = ci->xform;
- if (snapping_2d_transforms_to_pixel) {
- xform.elements[2] = xform.elements[2].floor();
- }
- xform = p_transform * xform;
-
- Rect2 global_rect = xform.xform(rect);
- global_rect.position += p_clip_rect.position;
-
- if (ci->use_parent_material && p_material_owner) {
- ci->material_owner = p_material_owner;
- } else {
- p_material_owner = ci;
- ci->material_owner = nullptr;
- }
-
- Color modulate(ci->modulate.r * p_modulate.r, ci->modulate.g * p_modulate.g, ci->modulate.b * p_modulate.b, ci->modulate.a * p_modulate.a);
-
- if (modulate.a < 0.007) {
- return;
- }
-
- int child_item_count = ci->child_items.size();
- Item **child_items = ci->child_items.ptrw();
-
- if (ci->clip) {
- if (p_canvas_clip != nullptr) {
- ci->final_clip_rect = p_canvas_clip->final_clip_rect.intersection(global_rect);
- } else {
- ci->final_clip_rect = global_rect;
- }
- ci->final_clip_rect.position = ci->final_clip_rect.position.round();
- ci->final_clip_rect.size = ci->final_clip_rect.size.round();
- ci->final_clip_owner = ci;
-
- } else {
- ci->final_clip_owner = p_canvas_clip;
- }
-
- if (ci->sort_y) {
- if (ci->ysort_children_count == -1) {
- ci->ysort_children_count = 0;
- _collect_ysort_children(ci, Transform2D(), p_material_owner, nullptr, ci->ysort_children_count);
- }
-
- child_item_count = ci->ysort_children_count;
- child_items = (Item **)alloca(child_item_count * sizeof(Item *));
-
- int i = 0;
- _collect_ysort_children(ci, Transform2D(), p_material_owner, child_items, i);
-
- SortArray<Item *, ItemPtrSort> sorter;
- sorter.sort(child_items, child_item_count);
- }
-
- if (ci->z_relative) {
- p_z = CLAMP(p_z + ci->z_index, RS::CANVAS_ITEM_Z_MIN, RS::CANVAS_ITEM_Z_MAX);
- } else {
- p_z = ci->z_index;
- }
-
- RendererCanvasRender::Item *canvas_group_from = nullptr;
- bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr);
- if (use_canvas_group) {
- int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
- canvas_group_from = z_last_list[zidx];
- }
-
- for (int i = 0; i < child_item_count; i++) {
- if ((!child_items[i]->behind && !use_canvas_group) || (ci->sort_y && child_items[i]->sort_y)) {
- continue;
- }
- if (ci->sort_y) {
- _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner);
- } else {
- _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner);
- }
- }
-
+void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform) {
if (ci->copy_back_buffer) {
ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect);
}
@@ -228,8 +137,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
// We have two choices now, if user has drawn something, we must assume users wants to draw the "mask", so compute the size based on this.
// If nothing has been drawn, we just take it over and draw it ourselves.
- if (ci->canvas_group->fit_empty && (ci->commands == nullptr ||
- (ci->commands->next == nullptr && ci->commands->type == Item::Command::TYPE_RECT && (static_cast<Item::CommandRect *>(ci->commands)->flags & RendererCanvasRender::CANVAS_RECT_IS_GROUP)))) {
+ if (ci->canvas_group->fit_empty && (ci->commands == nullptr || (ci->commands->next == nullptr && ci->commands->type == RendererCanvasCull::Item::Command::TYPE_RECT && (static_cast<RendererCanvasCull::Item::CommandRect *>(ci->commands)->flags & RendererCanvasRender::CANVAS_RECT_IS_GROUP)))) {
// No commands, or sole command is the one used to draw, so we (re)create the draw command.
ci->clear();
@@ -264,42 +172,163 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
}
}
- if (ci->update_when_visible) {
- RenderingServerDefault::redraw_request();
+ if (((ci->commands != nullptr || ci->visibility_notifier) && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
+ //something to draw?
+
+ if (ci->update_when_visible) {
+ RenderingServerDefault::redraw_request();
+ }
+
+ if (ci->commands != nullptr) {
+ ci->final_transform = xform;
+ ci->final_modulate = modulate * ci->self_modulate;
+ ci->global_rect_cache = global_rect;
+ ci->global_rect_cache.position -= p_clip_rect.position;
+ ci->light_masked = false;
+
+ int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
+
+ if (z_last_list[zidx]) {
+ z_last_list[zidx]->next = ci;
+ z_last_list[zidx] = ci;
+
+ } else {
+ z_list[zidx] = ci;
+ z_last_list[zidx] = ci;
+ }
+
+ ci->z_final = p_z;
+
+ ci->next = nullptr;
+ }
+
+ if (ci->visibility_notifier) {
+ if (!ci->visibility_notifier->visible_element.in_list()) {
+ visibility_notifier_list.add(&ci->visibility_notifier->visible_element);
+ ci->visibility_notifier->just_visible = true;
+ }
+
+ ci->visibility_notifier->visible_in_frame = RSG::rasterizer->get_frame_number();
+ }
}
+}
- if ((ci->commands != nullptr && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
- //something to draw?
- ci->final_transform = xform;
- ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a);
- ci->global_rect_cache = global_rect;
- ci->global_rect_cache.position -= p_clip_rect.position;
- ci->light_masked = false;
+void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort) {
+ Item *ci = p_canvas_item;
- int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
+ if (!ci->visible) {
+ return;
+ }
+
+ if (ci->children_order_dirty) {
+ ci->child_items.sort_custom<ItemIndexSort>();
+ ci->children_order_dirty = false;
+ }
- if (z_last_list[zidx]) {
- z_last_list[zidx]->next = ci;
- z_last_list[zidx] = ci;
+ Rect2 rect = ci->get_rect();
- } else {
- z_list[zidx] = ci;
- z_last_list[zidx] = ci;
+ if (ci->visibility_notifier) {
+ if (ci->visibility_notifier->area.size != Vector2()) {
+ rect = rect.merge(ci->visibility_notifier->area);
}
+ }
+
+ Transform2D xform = ci->xform;
+ if (snapping_2d_transforms_to_pixel) {
+ xform.elements[2] = xform.elements[2].floor();
+ }
+ xform = p_transform * xform;
- ci->z_final = p_z;
+ Rect2 global_rect = xform.xform(rect);
+ global_rect.position += p_clip_rect.position;
- ci->next = nullptr;
+ if (ci->use_parent_material && p_material_owner) {
+ ci->material_owner = p_material_owner;
+ } else {
+ p_material_owner = ci;
+ ci->material_owner = nullptr;
}
- for (int i = 0; i < child_item_count; i++) {
- if (child_items[i]->behind || use_canvas_group || (ci->sort_y && child_items[i]->sort_y)) {
- continue;
+ Color modulate(ci->modulate.r * p_modulate.r, ci->modulate.g * p_modulate.g, ci->modulate.b * p_modulate.b, ci->modulate.a * p_modulate.a);
+
+ if (modulate.a < 0.007) {
+ return;
+ }
+
+ int child_item_count = ci->child_items.size();
+ Item **child_items = ci->child_items.ptrw();
+
+ if (ci->clip) {
+ if (p_canvas_clip != nullptr) {
+ ci->final_clip_rect = p_canvas_clip->final_clip_rect.intersection(global_rect);
+ } else {
+ ci->final_clip_rect = global_rect;
}
- if (ci->sort_y) {
- _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner);
+ ci->final_clip_rect.position = ci->final_clip_rect.position.round();
+ ci->final_clip_rect.size = ci->final_clip_rect.size.round();
+ ci->final_clip_owner = ci;
+
+ } else {
+ ci->final_clip_owner = p_canvas_clip;
+ }
+
+ if (ci->z_relative) {
+ p_z = CLAMP(p_z + ci->z_index, RS::CANVAS_ITEM_Z_MIN, RS::CANVAS_ITEM_Z_MAX);
+ } else {
+ p_z = ci->z_index;
+ }
+
+ if (ci->sort_y) {
+ if (allow_y_sort) {
+ if (ci->ysort_children_count == -1) {
+ ci->ysort_children_count = 0;
+ _collect_ysort_children(ci, Transform2D(), p_material_owner, nullptr, ci->ysort_children_count);
+ }
+
+ child_item_count = ci->ysort_children_count + 1;
+ child_items = (Item **)alloca(child_item_count * sizeof(Item *));
+
+ child_items[0] = ci;
+ int i = 1;
+ _collect_ysort_children(ci, Transform2D(), p_material_owner, child_items, i);
+ ci->ysort_xform = ci->xform.affine_inverse();
+
+ SortArray<Item *, ItemPtrSort> sorter;
+ sorter.sort(child_items, child_item_count);
+
+ for (i = 0; i < child_item_count; i++) {
+ _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false);
+ }
} else {
- _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner);
+ RendererCanvasRender::Item *canvas_group_from = nullptr;
+ bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr);
+ if (use_canvas_group) {
+ int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
+ canvas_group_from = z_last_list[zidx];
+ }
+
+ _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform);
+ }
+ } else {
+ RendererCanvasRender::Item *canvas_group_from = nullptr;
+ bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr);
+ if (use_canvas_group) {
+ int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
+ canvas_group_from = z_last_list[zidx];
+ }
+
+ for (int i = 0; i < child_item_count; i++) {
+ if (!child_items[i]->behind && !use_canvas_group) {
+ continue;
+ }
+ _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true);
+ }
+ _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform);
+ for (int i = 0; i < child_item_count; i++) {
+ if (child_items[i]->behind || use_canvas_group) {
+ continue;
+ }
+ _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true);
}
}
}
@@ -362,14 +391,13 @@ RID RendererCanvasCull::canvas_allocate() {
return canvas_owner.allocate_rid();
}
void RendererCanvasCull::canvas_initialize(RID p_rid) {
- Canvas *canvas = memnew(Canvas);
- canvas_owner.initialize_rid(p_rid, canvas);
+ canvas_owner.initialize_rid(p_rid);
}
void RendererCanvasCull::canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) {
- Canvas *canvas = canvas_owner.getornull(p_canvas);
+ Canvas *canvas = canvas_owner.get_or_null(p_canvas);
ERR_FAIL_COND(!canvas);
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
int idx = canvas->find_item(canvas_item);
@@ -378,7 +406,7 @@ void RendererCanvasCull::canvas_set_item_mirroring(RID p_canvas, RID p_item, con
}
void RendererCanvasCull::canvas_set_modulate(RID p_canvas, const Color &p_color) {
- Canvas *canvas = canvas_owner.getornull(p_canvas);
+ Canvas *canvas = canvas_owner.get_or_null(p_canvas);
ERR_FAIL_COND(!canvas);
canvas->modulate = p_color;
}
@@ -388,7 +416,7 @@ void RendererCanvasCull::canvas_set_disable_scale(bool p_disable) {
}
void RendererCanvasCull::canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) {
- Canvas *canvas = canvas_owner.getornull(p_canvas);
+ Canvas *canvas = canvas_owner.get_or_null(p_canvas);
ERR_FAIL_COND(!canvas);
canvas->parent = p_parent;
@@ -399,20 +427,19 @@ RID RendererCanvasCull::canvas_item_allocate() {
return canvas_item_owner.allocate_rid();
}
void RendererCanvasCull::canvas_item_initialize(RID p_rid) {
- Item *canvas_item = memnew(Item);
- canvas_item_owner.initialize_rid(p_rid, canvas_item);
+ canvas_item_owner.initialize_rid(p_rid);
}
void RendererCanvasCull::canvas_item_set_parent(RID p_item, RID p_parent) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
if (canvas_item->parent.is_valid()) {
if (canvas_owner.owns(canvas_item->parent)) {
- Canvas *canvas = canvas_owner.getornull(canvas_item->parent);
+ Canvas *canvas = canvas_owner.get_or_null(canvas_item->parent);
canvas->erase_item(canvas_item);
} else if (canvas_item_owner.owns(canvas_item->parent)) {
- Item *item_owner = canvas_item_owner.getornull(canvas_item->parent);
+ Item *item_owner = canvas_item_owner.get_or_null(canvas_item->parent);
item_owner->child_items.erase(canvas_item);
if (item_owner->sort_y) {
@@ -425,13 +452,13 @@ void RendererCanvasCull::canvas_item_set_parent(RID p_item, RID p_parent) {
if (p_parent.is_valid()) {
if (canvas_owner.owns(p_parent)) {
- Canvas *canvas = canvas_owner.getornull(p_parent);
+ Canvas *canvas = canvas_owner.get_or_null(p_parent);
Canvas::ChildItem ci;
ci.item = canvas_item;
canvas->child_items.push_back(ci);
canvas->children_order_dirty = true;
} else if (canvas_item_owner.owns(p_parent)) {
- Item *item_owner = canvas_item_owner.getornull(p_parent);
+ Item *item_owner = canvas_item_owner.get_or_null(p_parent);
item_owner->child_items.push_back(canvas_item);
item_owner->children_order_dirty = true;
@@ -448,7 +475,7 @@ void RendererCanvasCull::canvas_item_set_parent(RID p_item, RID p_parent) {
}
void RendererCanvasCull::canvas_item_set_visible(RID p_item, bool p_visible) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->visible = p_visible;
@@ -457,35 +484,35 @@ void RendererCanvasCull::canvas_item_set_visible(RID p_item, bool p_visible) {
}
void RendererCanvasCull::canvas_item_set_light_mask(RID p_item, int p_mask) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->light_mask = p_mask;
}
void RendererCanvasCull::canvas_item_set_transform(RID p_item, const Transform2D &p_transform) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->xform = p_transform;
}
void RendererCanvasCull::canvas_item_set_clip(RID p_item, bool p_clip) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->clip = p_clip;
}
void RendererCanvasCull::canvas_item_set_distance_field_mode(RID p_item, bool p_enable) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->distance_field = p_enable;
}
void RendererCanvasCull::canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->custom_rect = p_custom_rect;
@@ -493,35 +520,35 @@ void RendererCanvasCull::canvas_item_set_custom_rect(RID p_item, bool p_custom_r
}
void RendererCanvasCull::canvas_item_set_modulate(RID p_item, const Color &p_color) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->modulate = p_color;
}
void RendererCanvasCull::canvas_item_set_self_modulate(RID p_item, const Color &p_color) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->self_modulate = p_color;
}
void RendererCanvasCull::canvas_item_set_draw_behind_parent(RID p_item, bool p_enable) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->behind = p_enable;
}
void RendererCanvasCull::canvas_item_set_update_when_visible(RID p_item, bool p_update) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->update_when_visible = p_update;
}
void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandPrimitive *line = canvas_item->alloc_command<Item::CommandPrimitive>();
@@ -545,7 +572,7 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from,
void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) {
ERR_FAIL_COND(p_points.size() < 2);
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Color color = Color(1, 1, 1, 1);
@@ -611,17 +638,19 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
j2 = j + 1;
- Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5;
+ Vector2 dir = (t + prev_t).normalized();
+ Vector2 tangent = dir * p_width * 0.5;
+ Vector2 border = dir * 2.0;
Vector2 pos = p_points[i];
points_ptr[j] = pos + tangent;
points_ptr[j2] = pos - tangent;
- points_top_ptr[j] = pos + tangent + tangent;
+ points_top_ptr[j] = pos + tangent + border;
points_top_ptr[j2] = pos + tangent;
points_bottom_ptr[j] = pos - tangent;
- points_bottom_ptr[j2] = pos - tangent - tangent;
+ points_bottom_ptr[j2] = pos - tangent - border;
if (i < p_colors.size()) {
color = p_colors[i];
@@ -684,7 +713,7 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
ERR_FAIL_COND(p_points.size() < 2);
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
@@ -700,7 +729,7 @@ void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Poin
}
void RendererCanvasCull::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
@@ -710,7 +739,7 @@ void RendererCanvasCull::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, c
}
void RendererCanvasCull::canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandPolygon *circle = canvas_item->alloc_command<Item::CommandPolygon>();
@@ -746,7 +775,7 @@ void RendererCanvasCull::canvas_item_add_circle(RID p_item, const Point2 &p_pos,
}
void RendererCanvasCull::canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile, const Color &p_modulate, bool p_transpose) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
@@ -776,8 +805,42 @@ void RendererCanvasCull::canvas_item_add_texture_rect(RID p_item, const Rect2 &p
rect->texture = p_texture;
}
+void RendererCanvasCull::canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, int p_outline_size, float p_px_range) {
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
+ ERR_FAIL_COND(!rect);
+ rect->modulate = p_modulate;
+ rect->rect = p_rect;
+
+ rect->texture = p_texture;
+
+ rect->source = p_src_rect;
+ rect->flags = RendererCanvasRender::CANVAS_RECT_REGION | RendererCanvasRender::CANVAS_RECT_MSDF;
+
+ if (p_rect.size.x < 0) {
+ rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H;
+ rect->rect.size.x = -rect->rect.size.x;
+ }
+ if (p_src_rect.size.x < 0) {
+ rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_H;
+ rect->source.size.x = -rect->source.size.x;
+ }
+ if (p_rect.size.y < 0) {
+ rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V;
+ rect->rect.size.y = -rect->rect.size.y;
+ }
+ if (p_src_rect.size.y < 0) {
+ rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_V;
+ rect->source.size.y = -rect->source.size.y;
+ }
+ rect->outline = p_outline_size;
+ rect->px_range = p_px_range;
+}
+
void RendererCanvasCull::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
@@ -818,7 +881,7 @@ void RendererCanvasCull::canvas_item_add_texture_rect_region(RID p_item, const R
}
void RendererCanvasCull::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode, RS::NinePatchAxisMode p_y_axis_mode, bool p_draw_center, const Color &p_modulate) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandNinePatch *style = canvas_item->alloc_command<Item::CommandNinePatch>();
@@ -842,7 +905,7 @@ void RendererCanvasCull::canvas_item_add_primitive(RID p_item, const Vector<Poin
uint32_t pc = p_points.size();
ERR_FAIL_COND(pc == 0 || pc > 4);
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandPrimitive *prim = canvas_item->alloc_command<Item::CommandPrimitive>();
@@ -868,7 +931,7 @@ void RendererCanvasCull::canvas_item_add_primitive(RID p_item, const Vector<Poin
}
void RendererCanvasCull::canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
#ifdef DEBUG_ENABLED
int pointcount = p_points.size();
@@ -889,7 +952,7 @@ void RendererCanvasCull::canvas_item_add_polygon(RID p_item, const Vector<Point2
}
void RendererCanvasCull::canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights, RID p_texture, int p_count) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
int vertex_count = p_points.size();
@@ -912,7 +975,7 @@ void RendererCanvasCull::canvas_item_add_triangle_array(RID p_item, const Vector
}
void RendererCanvasCull::canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandTransform *tr = canvas_item->alloc_command<Item::CommandTransform>();
@@ -921,7 +984,7 @@ void RendererCanvasCull::canvas_item_add_set_transform(RID p_item, const Transfo
}
void RendererCanvasCull::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
ERR_FAIL_COND(!p_mesh.is_valid());
@@ -940,7 +1003,7 @@ void RendererCanvasCull::canvas_item_add_mesh(RID p_item, const RID &p_mesh, con
}
void RendererCanvasCull::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandParticles *part = canvas_item->alloc_command<Item::CommandParticles>();
@@ -954,7 +1017,7 @@ void RendererCanvasCull::canvas_item_add_particles(RID p_item, RID p_particles,
}
void RendererCanvasCull::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandMultiMesh *mm = canvas_item->alloc_command<Item::CommandMultiMesh>();
@@ -965,7 +1028,7 @@ void RendererCanvasCull::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p
}
void RendererCanvasCull::canvas_item_add_clip_ignore(RID p_item, bool p_ignore) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandClipIgnore *ci = canvas_item->alloc_command<Item::CommandClipIgnore>();
@@ -973,8 +1036,20 @@ void RendererCanvasCull::canvas_item_add_clip_ignore(RID p_item, bool p_ignore)
ci->ignore = p_ignore;
}
+void RendererCanvasCull::canvas_item_add_animation_slice(RID p_item, double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset) {
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandAnimationSlice *as = canvas_item->alloc_command<Item::CommandAnimationSlice>();
+ ERR_FAIL_COND(!as);
+ as->animation_length = p_animation_length;
+ as->slice_begin = p_slice_begin;
+ as->slice_end = p_slice_end;
+ as->offset = p_offset;
+}
+
void RendererCanvasCull::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->sort_y = p_enable;
@@ -985,21 +1060,21 @@ void RendererCanvasCull::canvas_item_set_sort_children_by_y(RID p_item, bool p_e
void RendererCanvasCull::canvas_item_set_z_index(RID p_item, int p_z) {
ERR_FAIL_COND(p_z < RS::CANVAS_ITEM_Z_MIN || p_z > RS::CANVAS_ITEM_Z_MAX);
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->z_index = p_z;
}
void RendererCanvasCull::canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->z_relative = p_enable;
}
void RendererCanvasCull::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
if (canvas_item->skeleton == p_skeleton) {
return;
@@ -1028,7 +1103,7 @@ void RendererCanvasCull::canvas_item_attach_skeleton(RID p_item, RID p_skeleton)
}
void RendererCanvasCull::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
if (p_enable && (canvas_item->copy_back_buffer == nullptr)) {
canvas_item->copy_back_buffer = memnew(RendererCanvasRender::Item::CopyBackBuffer);
@@ -1045,25 +1120,25 @@ void RendererCanvasCull::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_e
}
void RendererCanvasCull::canvas_item_clear(RID p_item) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->clear();
}
void RendererCanvasCull::canvas_item_set_draw_index(RID p_item, int p_index) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->index = p_index;
if (canvas_item_owner.owns(canvas_item->parent)) {
- Item *canvas_item_parent = canvas_item_owner.getornull(canvas_item->parent);
+ Item *canvas_item_parent = canvas_item_owner.get_or_null(canvas_item->parent);
canvas_item_parent->children_order_dirty = true;
return;
}
- Canvas *canvas = canvas_owner.getornull(canvas_item->parent);
+ Canvas *canvas = canvas_owner.get_or_null(canvas_item->parent);
if (canvas) {
canvas->children_order_dirty = true;
return;
@@ -1071,21 +1146,41 @@ void RendererCanvasCull::canvas_item_set_draw_index(RID p_item, int p_index) {
}
void RendererCanvasCull::canvas_item_set_material(RID p_item, RID p_material) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->material = p_material;
}
void RendererCanvasCull::canvas_item_set_use_parent_material(RID p_item, bool p_enable) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
canvas_item->use_parent_material = p_enable;
}
+void RendererCanvasCull::canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable) {
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ if (p_enable) {
+ if (!canvas_item->visibility_notifier) {
+ canvas_item->visibility_notifier = visibility_notifier_allocator.alloc();
+ }
+ canvas_item->visibility_notifier->area = p_area;
+ canvas_item->visibility_notifier->enter_callable = p_enter_callable;
+ canvas_item->visibility_notifier->exit_callable = p_exit_callable;
+
+ } else {
+ if (canvas_item->visibility_notifier) {
+ visibility_notifier_allocator.free(canvas_item->visibility_notifier);
+ canvas_item->visibility_notifier = nullptr;
+ }
+ }
+}
+
void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) {
- Item *canvas_item = canvas_item_owner.getornull(p_item);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
if (p_mode == RS::CANVAS_GROUP_MODE_DISABLED) {
@@ -1109,13 +1204,13 @@ RID RendererCanvasCull::canvas_light_allocate() {
return canvas_light_owner.allocate_rid();
}
void RendererCanvasCull::canvas_light_initialize(RID p_rid) {
- RendererCanvasRender::Light *clight = memnew(RendererCanvasRender::Light);
+ canvas_light_owner.initialize_rid(p_rid);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_rid);
clight->light_internal = RSG::canvas_render->light_create();
- return canvas_light_owner.initialize_rid(p_rid, clight);
}
void RendererCanvasCull::canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
if (clight->mode == p_mode) {
@@ -1136,11 +1231,11 @@ void RendererCanvasCull::canvas_light_set_mode(RID p_light, RS::CanvasLightMode
}
void RendererCanvasCull::canvas_light_attach_to_canvas(RID p_light, RID p_canvas) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
if (clight->canvas.is_valid()) {
- Canvas *canvas = canvas_owner.getornull(clight->canvas);
+ Canvas *canvas = canvas_owner.get_or_null(clight->canvas);
if (clight->mode == RS::CANVAS_LIGHT_MODE_POINT) {
canvas->lights.erase(clight);
} else {
@@ -1155,7 +1250,7 @@ void RendererCanvasCull::canvas_light_attach_to_canvas(RID p_light, RID p_canvas
clight->canvas = p_canvas;
if (clight->canvas.is_valid()) {
- Canvas *canvas = canvas_owner.getornull(clight->canvas);
+ Canvas *canvas = canvas_owner.get_or_null(clight->canvas);
if (clight->mode == RS::CANVAS_LIGHT_MODE_POINT) {
canvas->lights.insert(clight);
} else {
@@ -1165,28 +1260,28 @@ void RendererCanvasCull::canvas_light_attach_to_canvas(RID p_light, RID p_canvas
}
void RendererCanvasCull::canvas_light_set_enabled(RID p_light, bool p_enabled) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->enabled = p_enabled;
}
void RendererCanvasCull::canvas_light_set_texture_scale(RID p_light, float p_scale) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->scale = p_scale;
}
void RendererCanvasCull::canvas_light_set_transform(RID p_light, const Transform2D &p_transform) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->xform = p_transform;
}
void RendererCanvasCull::canvas_light_set_texture(RID p_light, RID p_texture) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
if (clight->texture == p_texture) {
@@ -1198,35 +1293,35 @@ void RendererCanvasCull::canvas_light_set_texture(RID p_light, RID p_texture) {
}
void RendererCanvasCull::canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->texture_offset = p_offset;
}
void RendererCanvasCull::canvas_light_set_color(RID p_light, const Color &p_color) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->color = p_color;
}
void RendererCanvasCull::canvas_light_set_height(RID p_light, float p_height) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->height = p_height;
}
void RendererCanvasCull::canvas_light_set_energy(RID p_light, float p_energy) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->energy = p_energy;
}
void RendererCanvasCull::canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->z_min = p_min_z;
@@ -1234,7 +1329,7 @@ void RendererCanvasCull::canvas_light_set_z_range(RID p_light, int p_min_z, int
}
void RendererCanvasCull::canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->layer_max = p_max_layer;
@@ -1242,35 +1337,35 @@ void RendererCanvasCull::canvas_light_set_layer_range(RID p_light, int p_min_lay
}
void RendererCanvasCull::canvas_light_set_item_cull_mask(RID p_light, int p_mask) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->item_mask = p_mask;
}
void RendererCanvasCull::canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->item_shadow_mask = p_mask;
}
void RendererCanvasCull::canvas_light_set_directional_distance(RID p_light, float p_distance) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->directional_distance = p_distance;
}
void RendererCanvasCull::canvas_light_set_blend_mode(RID p_light, RS::CanvasLightBlendMode p_mode) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->blend_mode = p_mode;
}
void RendererCanvasCull::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
if (clight->use_shadow == p_enabled) {
@@ -1282,21 +1377,21 @@ void RendererCanvasCull::canvas_light_set_shadow_enabled(RID p_light, bool p_ena
}
void RendererCanvasCull::canvas_light_set_shadow_filter(RID p_light, RS::CanvasLightShadowFilter p_filter) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->shadow_filter = p_filter;
}
void RendererCanvasCull::canvas_light_set_shadow_color(RID p_light, const Color &p_color) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->shadow_color = p_color;
}
void RendererCanvasCull::canvas_light_set_shadow_smooth(RID p_light, float p_smooth) {
- RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light);
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_COND(!clight);
clight->shadow_smooth = p_smooth;
}
@@ -1305,17 +1400,15 @@ RID RendererCanvasCull::canvas_light_occluder_allocate() {
return canvas_light_occluder_owner.allocate_rid();
}
void RendererCanvasCull::canvas_light_occluder_initialize(RID p_rid) {
- RendererCanvasRender::LightOccluderInstance *occluder = memnew(RendererCanvasRender::LightOccluderInstance);
-
- return canvas_light_occluder_owner.initialize_rid(p_rid, occluder);
+ return canvas_light_occluder_owner.initialize_rid(p_rid);
}
void RendererCanvasCull::canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) {
- RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
+ RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
ERR_FAIL_COND(!occluder);
if (occluder->canvas.is_valid()) {
- Canvas *canvas = canvas_owner.getornull(occluder->canvas);
+ Canvas *canvas = canvas_owner.get_or_null(occluder->canvas);
canvas->occluders.erase(occluder);
}
@@ -1326,24 +1419,24 @@ void RendererCanvasCull::canvas_light_occluder_attach_to_canvas(RID p_occluder,
occluder->canvas = p_canvas;
if (occluder->canvas.is_valid()) {
- Canvas *canvas = canvas_owner.getornull(occluder->canvas);
+ Canvas *canvas = canvas_owner.get_or_null(occluder->canvas);
canvas->occluders.insert(occluder);
}
}
void RendererCanvasCull::canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) {
- RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
+ RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
ERR_FAIL_COND(!occluder);
occluder->enabled = p_enabled;
}
void RendererCanvasCull::canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon) {
- RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
+ RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
ERR_FAIL_COND(!occluder);
if (occluder->polygon.is_valid()) {
- LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_polygon);
+ LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_polygon);
if (occluder_poly) {
occluder_poly->owners.erase(occluder);
}
@@ -1353,7 +1446,7 @@ void RendererCanvasCull::canvas_light_occluder_set_polygon(RID p_occluder, RID p
occluder->occluder = RID();
if (occluder->polygon.is_valid()) {
- LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_polygon);
+ LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_polygon);
if (!occluder_poly) {
occluder->polygon = RID();
ERR_FAIL_COND(!occluder_poly);
@@ -1367,19 +1460,19 @@ void RendererCanvasCull::canvas_light_occluder_set_polygon(RID p_occluder, RID p
}
void RendererCanvasCull::canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable) {
- RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
+ RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
ERR_FAIL_COND(!occluder);
}
void RendererCanvasCull::canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) {
- RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
+ RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
ERR_FAIL_COND(!occluder);
occluder->xform = p_xform;
}
void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) {
- RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
+ RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
ERR_FAIL_COND(!occluder);
occluder->light_mask = p_mask;
@@ -1389,13 +1482,13 @@ RID RendererCanvasCull::canvas_occluder_polygon_allocate() {
return canvas_light_occluder_polygon_owner.allocate_rid();
}
void RendererCanvasCull::canvas_occluder_polygon_initialize(RID p_rid) {
- LightOccluderPolygon *occluder_poly = memnew(LightOccluderPolygon);
+ canvas_light_occluder_polygon_owner.initialize_rid(p_rid);
+ LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_rid);
occluder_poly->occluder = RSG::canvas_render->occluder_polygon_create();
- return canvas_light_occluder_polygon_owner.initialize_rid(p_rid, occluder_poly);
}
void RendererCanvasCull::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) {
- LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_occluder_polygon);
+ LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_occluder_polygon);
ERR_FAIL_COND(!occluder_poly);
uint32_t pc = p_shape.size();
@@ -1419,7 +1512,7 @@ void RendererCanvasCull::canvas_occluder_polygon_set_shape(RID p_occluder_polygo
}
void RendererCanvasCull::canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode) {
- LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_occluder_polygon);
+ LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_occluder_polygon);
ERR_FAIL_COND(!occluder_poly);
occluder_poly->cull_mode = p_mode;
RSG::canvas_render->occluder_polygon_set_cull_mode(occluder_poly->occluder, p_mode);
@@ -1456,23 +1549,61 @@ void RendererCanvasCull::canvas_texture_set_texture_repeat(RID p_canvas_texture,
}
void RendererCanvasCull::canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) {
- Item *ci = canvas_item_owner.getornull(p_item);
+ Item *ci = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!ci);
ci->texture_filter = p_filter;
}
void RendererCanvasCull::canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) {
- Item *ci = canvas_item_owner.getornull(p_item);
+ Item *ci = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!ci);
ci->texture_repeat = p_repeat;
}
+void RendererCanvasCull::update_visibility_notifiers() {
+ SelfList<Item::VisibilityNotifierData> *E = visibility_notifier_list.first();
+ while (E) {
+ SelfList<Item::VisibilityNotifierData> *N = E->next();
+
+ Item::VisibilityNotifierData *visibility_notifier = E->self();
+ if (visibility_notifier->just_visible) {
+ visibility_notifier->just_visible = false;
+
+ if (!visibility_notifier->enter_callable.is_null()) {
+ if (RSG::threaded) {
+ visibility_notifier->enter_callable.call_deferred(nullptr, 0);
+ } else {
+ Callable::CallError ce;
+ Variant ret;
+ visibility_notifier->enter_callable.call(nullptr, 0, ret, ce);
+ }
+ }
+ } else {
+ if (visibility_notifier->visible_in_frame != RSG::rasterizer->get_frame_number()) {
+ visibility_notifier_list.remove(E);
+
+ if (!visibility_notifier->exit_callable.is_null()) {
+ if (RSG::threaded) {
+ visibility_notifier->exit_callable.call_deferred(nullptr, 0);
+ } else {
+ Callable::CallError ce;
+ Variant ret;
+ visibility_notifier->exit_callable.call(nullptr, 0, ret, ce);
+ }
+ }
+ }
+ }
+
+ E = N;
+ }
+}
+
bool RendererCanvasCull::free(RID p_rid) {
if (canvas_owner.owns(p_rid)) {
- Canvas *canvas = canvas_owner.getornull(p_rid);
+ Canvas *canvas = canvas_owner.get_or_null(p_rid);
ERR_FAIL_COND_V(!canvas, false);
while (canvas->viewports.size()) {
- RendererViewport::Viewport *vp = RSG::viewport->viewport_owner.getornull(canvas->viewports.front()->get());
+ RendererViewport::Viewport *vp = RSG::viewport->viewport_owner.get_or_null(canvas->viewports.front()->get());
ERR_FAIL_COND_V(!vp, true);
Map<RID, RendererViewport::Viewport::CanvasData>::Element *E = vp->canvas_map.find(p_rid);
@@ -1496,18 +1627,16 @@ bool RendererCanvasCull::free(RID p_rid) {
canvas_owner.free(p_rid);
- memdelete(canvas);
-
} else if (canvas_item_owner.owns(p_rid)) {
- Item *canvas_item = canvas_item_owner.getornull(p_rid);
+ Item *canvas_item = canvas_item_owner.get_or_null(p_rid);
ERR_FAIL_COND_V(!canvas_item, true);
if (canvas_item->parent.is_valid()) {
if (canvas_owner.owns(canvas_item->parent)) {
- Canvas *canvas = canvas_owner.getornull(canvas_item->parent);
+ Canvas *canvas = canvas_owner.get_or_null(canvas_item->parent);
canvas->erase_item(canvas_item);
} else if (canvas_item_owner.owns(canvas_item->parent)) {
- Item *item_owner = canvas_item_owner.getornull(canvas_item->parent);
+ Item *item_owner = canvas_item_owner.get_or_null(canvas_item->parent);
item_owner->child_items.erase(canvas_item);
if (item_owner->sort_y) {
@@ -1520,6 +1649,10 @@ bool RendererCanvasCull::free(RID p_rid) {
canvas_item->child_items[i]->parent = RID();
}
+ if (canvas_item->visibility_notifier != nullptr) {
+ visibility_notifier_allocator.free(canvas_item->visibility_notifier);
+ }
+
/*
if (canvas_item->material) {
canvas_item->material->owners.erase(canvas_item);
@@ -1528,14 +1661,12 @@ bool RendererCanvasCull::free(RID p_rid) {
canvas_item_owner.free(p_rid);
- memdelete(canvas_item);
-
} else if (canvas_light_owner.owns(p_rid)) {
- RendererCanvasRender::Light *canvas_light = canvas_light_owner.getornull(p_rid);
+ RendererCanvasRender::Light *canvas_light = canvas_light_owner.get_or_null(p_rid);
ERR_FAIL_COND_V(!canvas_light, true);
if (canvas_light->canvas.is_valid()) {
- Canvas *canvas = canvas_owner.getornull(canvas_light->canvas);
+ Canvas *canvas = canvas_owner.get_or_null(canvas_light->canvas);
if (canvas) {
canvas->lights.erase(canvas_light);
}
@@ -1544,29 +1675,27 @@ bool RendererCanvasCull::free(RID p_rid) {
RSG::canvas_render->free(canvas_light->light_internal);
canvas_light_owner.free(p_rid);
- memdelete(canvas_light);
} else if (canvas_light_occluder_owner.owns(p_rid)) {
- RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_rid);
+ RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_rid);
ERR_FAIL_COND_V(!occluder, true);
if (occluder->polygon.is_valid()) {
- LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(occluder->polygon);
+ LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(occluder->polygon);
if (occluder_poly) {
occluder_poly->owners.erase(occluder);
}
}
if (occluder->canvas.is_valid() && canvas_owner.owns(occluder->canvas)) {
- Canvas *canvas = canvas_owner.getornull(occluder->canvas);
+ Canvas *canvas = canvas_owner.get_or_null(occluder->canvas);
canvas->occluders.erase(occluder);
}
canvas_light_occluder_owner.free(p_rid);
- memdelete(occluder);
} else if (canvas_light_occluder_polygon_owner.owns(p_rid)) {
- LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_rid);
+ LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_rid);
ERR_FAIL_COND_V(!occluder_poly, true);
RSG::canvas_render->free(occluder_poly->occluder);
@@ -1576,7 +1705,6 @@ bool RendererCanvasCull::free(RID p_rid) {
}
canvas_light_occluder_polygon_owner.free(p_rid);
- memdelete(occluder_poly);
} else {
return false;
}
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index b71f8e5a9a..bdd61123df 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -31,6 +31,7 @@
#ifndef RENDERING_SERVER_CANVAS_CULL_H
#define RENDERING_SERVER_CANVAS_CULL_H
+#include "core/templates/paged_allocator.h"
#include "renderer_compositor.h"
#include "renderer_viewport.h"
@@ -55,6 +56,20 @@ public:
Vector<Item *> child_items;
+ struct VisibilityNotifierData {
+ Rect2 area;
+ Callable enter_callable;
+ Callable exit_callable;
+ bool just_visible = false;
+ uint64_t visible_in_frame = 0;
+ SelfList<VisibilityNotifierData> visible_element;
+ VisibilityNotifierData() :
+ visible_element(this) {
+ }
+ };
+
+ VisibilityNotifierData *visibility_notifier = nullptr;
+
Item() {
children_order_dirty = true;
E = nullptr;
@@ -101,9 +116,9 @@ public:
}
};
- RID_PtrOwner<LightOccluderPolygon, true> canvas_light_occluder_polygon_owner;
+ RID_Owner<LightOccluderPolygon, true> canvas_light_occluder_polygon_owner;
- RID_PtrOwner<RendererCanvasRender::LightOccluderInstance, true> canvas_light_occluder_owner;
+ RID_Owner<RendererCanvasRender::LightOccluderInstance, true> canvas_light_occluder_owner;
struct Canvas : public RendererViewport::CanvasBase {
Set<RID> viewports;
@@ -137,7 +152,7 @@ public:
void erase_item(Item *p_item) {
int idx = find_item(p_item);
if (idx >= 0) {
- child_items.remove(idx);
+ child_items.remove_at(idx);
}
}
@@ -148,17 +163,22 @@ public:
}
};
- mutable RID_PtrOwner<Canvas, true> canvas_owner;
- RID_PtrOwner<Item, true> canvas_item_owner;
- RID_PtrOwner<RendererCanvasRender::Light, true> canvas_light_owner;
+ mutable RID_Owner<Canvas, true> canvas_owner;
+ RID_Owner<Item, true> canvas_item_owner;
+ RID_Owner<RendererCanvasRender::Light, true> canvas_light_owner;
bool disable_scale;
bool sdf_used = false;
bool snapping_2d_transforms_to_pixel = false;
+ PagedAllocator<Item::VisibilityNotifierData> visibility_notifier_allocator;
+ SelfList<Item::VisibilityNotifierData>::List visibility_notifier_list;
+
+ _FORCE_INLINE_ void _attach_canvas_item_for_draw(Item *ci, Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform);
+
private:
void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel);
- void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner);
+ void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort);
RendererCanvasRender::Item **z_list;
RendererCanvasRender::Item **z_last_list;
@@ -202,6 +222,7 @@ public:
void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color);
void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false);
void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false);
+ void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0);
void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode = RS::NINE_PATCH_STRETCH, RS::NinePatchAxisMode p_y_axis_mode = RS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1));
void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0);
void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID());
@@ -211,6 +232,8 @@ public:
void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture);
void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform);
void canvas_item_add_clip_ignore(RID p_item, bool p_ignore);
+ void canvas_item_add_animation_slice(RID p_item, double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset);
+
void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable);
void canvas_item_set_z_index(RID p_item, int p_z);
void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable);
@@ -224,6 +247,8 @@ public:
void canvas_item_set_use_parent_material(RID p_item, bool p_enable);
+ void canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable);
+
void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false);
RID canvas_light_allocate();
@@ -283,9 +308,11 @@ public:
void canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter);
void canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat);
+ void update_visibility_notifiers();
+
bool free(RID p_rid);
RendererCanvasCull();
~RendererCanvasCull();
};
-#endif // VISUALSERVERCANVAS_H
+#endif // RENDERING_SERVER_CANVAS_CULL_H
diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h
index 0e9ef616cb..04ddae4089 100644
--- a/servers/rendering/renderer_canvas_render.h
+++ b/servers/rendering/renderer_canvas_render.h
@@ -45,6 +45,7 @@ public:
CANVAS_RECT_TRANSPOSE = 16,
CANVAS_RECT_CLIP_UV = 32,
CANVAS_RECT_IS_GROUP = 64,
+ CANVAS_RECT_MSDF = 128,
};
struct Light {
@@ -180,6 +181,7 @@ public:
TYPE_PARTICLES,
TYPE_TRANSFORM,
TYPE_CLIP_IGNORE,
+ TYPE_ANIMATION_SLICE,
};
Command *next;
@@ -192,11 +194,15 @@ public:
Color modulate;
Rect2 source;
uint8_t flags;
+ float outline;
+ float px_range;
RID texture;
CommandRect() {
flags = 0;
+ outline = 0;
+ px_range = 1;
type = TYPE_RECT;
}
};
@@ -286,6 +292,17 @@ public:
}
};
+ struct CommandAnimationSlice : public Command {
+ double animation_length = 0;
+ double slice_begin = 0;
+ double slice_end = 0;
+ double offset = 0;
+
+ CommandAnimationSlice() {
+ type = TYPE_ANIMATION_SLICE;
+ }
+ };
+
struct ViewportRender {
RenderingServer *owner;
void *udata;
@@ -420,7 +437,6 @@ public:
if (found_xform) {
r = xf.xform(r);
- found_xform = false;
}
if (first) {
@@ -597,8 +613,6 @@ public:
virtual void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) = 0;
virtual void set_shadow_texture_size(int p_size) = 0;
- virtual void draw_window_margins(int *p_margins, RID *p_margin_textures) = 0;
-
virtual bool free(RID p_rid) = 0;
virtual void update() = 0;
diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp
index 8861522d34..80c4625261 100644
--- a/servers/rendering/renderer_compositor.cpp
+++ b/servers/rendering/renderer_compositor.cpp
@@ -30,6 +30,7 @@
#include "renderer_compositor.h"
+#include "core/config/project_settings.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
@@ -39,4 +40,12 @@ RendererCompositor *RendererCompositor::create() {
return _create_func();
}
+bool RendererCompositor::is_xr_enabled() const {
+ return xr_enabled;
+}
+
+RendererCompositor::RendererCompositor() {
+ xr_enabled = GLOBAL_GET("rendering/xr/enabled");
+}
+
RendererCanvasRender *RendererCanvasRender::singleton = nullptr;
diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h
index 41aaba0f4c..4526354d17 100644
--- a/servers/rendering/renderer_compositor.h
+++ b/servers/rendering/renderer_compositor.h
@@ -36,13 +36,38 @@
#include "core/templates/self_list.h"
#include "servers/rendering/renderer_canvas_render.h"
#include "servers/rendering/renderer_scene.h"
-#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/renderer_storage.h"
#include "servers/rendering_server.h"
+class RendererSceneRender;
+struct BlitToScreen {
+ RID render_target;
+ Rect2 src_rect = Rect2(0.0, 0.0, 1.0, 1.0);
+ Rect2i dst_rect;
+
+ struct {
+ bool use_layer = false;
+ uint32_t layer = 0;
+ } multi_view;
+
+ struct {
+ //lens distorted parameters for VR
+ bool apply = false;
+ Vector2 eye_center;
+ float k1 = 0.0;
+ float k2 = 0.0;
+
+ float upscale = 1.0;
+ float aspect_ratio = 1.0;
+ } lens_distortion;
+};
class RendererCompositor {
+private:
+ bool xr_enabled = false;
+
protected:
static RendererCompositor *(*_create_func)();
+ bool back_end = false;
public:
static RendererCompositor *create();
@@ -56,37 +81,18 @@ public:
virtual void initialize() = 0;
virtual void begin_frame(double frame_step) = 0;
- struct BlitToScreen {
- RID render_target;
- Rect2i rect;
-
- struct {
- bool use_layer = false;
- uint32_t layer = 0;
- } multi_view;
-
- struct {
- //lens distorted parameters for VR
- bool apply = false;
- Vector2 eye_center;
- float k1 = 0.0;
- float k2 = 0.0;
-
- float upscale = 1.0;
- float aspect_ratio = 1.0;
- } lens_distortion;
- };
-
virtual void prepare_for_blitting_render_targets() = 0;
virtual void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0;
virtual void end_frame(bool p_swap_buffers) = 0;
virtual void finalize() = 0;
virtual uint64_t get_frame_number() const = 0;
- virtual float get_frame_delta_time() const = 0;
+ virtual double get_frame_delta_time() const = 0;
- virtual bool is_low_end() const = 0;
+ _FORCE_INLINE_ virtual bool is_low_end() const { return back_end; };
+ virtual bool is_xr_enabled() const;
+ RendererCompositor();
virtual ~RendererCompositor() {}
};
diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp
index 2669a73014..4a98cf0831 100644
--- a/servers/rendering/renderer_rd/cluster_builder_rd.cpp
+++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp
@@ -374,7 +374,7 @@ void ClusterBuilderRD::setup(Size2i p_screen_size, uint32_t p_max_elements, RID
}
}
-void ClusterBuilderRD::begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y) {
+void ClusterBuilderRD::begin(const Transform3D &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y) {
view_xform = p_view_transform.affine_inverse();
projection = p_cam_projection;
z_near = projection.get_z_near();
@@ -460,14 +460,6 @@ void ClusterBuilderRD::bake_cluster() {
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ClusterBuilderSharedDataRD::ClusterRender::PushConstant));
uint32_t instances = 1;
-#if 0
- for (uint32_t j = i+1; j < element_count; j++) {
- if (elements[i].type!=elements[j].type) {
- break;
- }
- instances++;
- }
-#endif
RD::get_singleton()->draw_list_draw(draw_list, true, instances);
i += instances;
}
diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.h b/servers/rendering/renderer_rd/cluster_builder_rd.h
index dc1707b534..feafd4c2db 100644
--- a/servers/rendering/renderer_rd/cluster_builder_rd.h
+++ b/servers/rendering/renderer_rd/cluster_builder_rd.h
@@ -167,7 +167,7 @@ private:
uint32_t render_element_count = 0;
uint32_t render_element_max = 0;
- Transform view_xform;
+ Transform3D view_xform;
CameraMatrix adjusted_projection;
CameraMatrix projection;
float z_far = 0;
@@ -220,9 +220,9 @@ private:
public:
void setup(Size2i p_screen_size, uint32_t p_max_elements, RID p_depth_buffer, RID p_depth_buffer_sampler, RID p_color_buffer);
- void begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y);
+ void begin(const Transform3D &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y);
- _FORCE_INLINE_ void add_light(LightType p_type, const Transform &p_transform, float p_radius, float p_spot_aperture) {
+ _FORCE_INLINE_ void add_light(LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture) {
if (p_type == LIGHT_TYPE_OMNI && cluster_count_by_type[ELEMENT_TYPE_OMNI_LIGHT] == max_elements_by_type) {
return; //max number elements reached
}
@@ -232,10 +232,10 @@ public:
RenderElementData &e = render_elements[render_element_count];
- Transform xform = view_xform * p_transform;
+ Transform3D xform = view_xform * p_transform;
float radius = xform.basis.get_uniform_scale();
- if (radius > 0.98 || radius < 1.02) {
+ if (radius < 0.98 || radius > 1.02) {
xform.basis.orthonormalize();
}
@@ -289,7 +289,7 @@ public:
e.touches_near = min_d < z_near;
} else {
//contains camera inside light
- Plane base_plane(xform.origin, -xform.basis.get_axis(Vector3::AXIS_Z));
+ Plane base_plane(-xform.basis.get_axis(Vector3::AXIS_Z), xform.origin);
float dist = base_plane.distance_to(Vector3());
if (dist >= 0 && dist < radius) {
//inside, check angle
@@ -317,7 +317,7 @@ public:
render_element_count++;
}
- _FORCE_INLINE_ void add_box(BoxType p_box_type, const Transform &p_transform, const Vector3 &p_half_extents) {
+ _FORCE_INLINE_ void add_box(BoxType p_box_type, const Transform3D &p_transform, const Vector3 &p_half_extents) {
if (p_box_type == BOX_TYPE_DECAL && cluster_count_by_type[ELEMENT_TYPE_DECAL] == max_elements_by_type) {
return; //max number elements reached
}
@@ -326,7 +326,7 @@ public:
}
RenderElementData &e = render_elements[render_element_count];
- Transform xform = view_xform * p_transform;
+ Transform3D xform = view_xform * p_transform;
//extract scale and scale the matrix by it, makes things simpler
Vector3 scale = p_half_extents;
diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp
index 563e08fdcb..cf943901d4 100644
--- a/servers/rendering/renderer_rd/effects_rd.cpp
+++ b/servers/rendering/renderer_rd/effects_rd.cpp
@@ -34,21 +34,11 @@
#include "core/math/math_defs.h"
#include "core/os/os.h"
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "thirdparty/misc/cubemap_coeffs.h"
-static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_array) {
- p_array[0] = p_basis.elements[0][0];
- p_array[1] = p_basis.elements[1][0];
- p_array[2] = p_basis.elements[2][0];
- p_array[3] = 0;
- p_array[4] = p_basis.elements[0][1];
- p_array[5] = p_basis.elements[1][1];
- p_array[6] = p_basis.elements[2][1];
- p_array[7] = 0;
- p_array[8] = p_basis.elements[0][2];
- p_array[9] = p_basis.elements[1][2];
- p_array[10] = p_basis.elements[2][2];
- p_array[11] = 0;
+bool EffectsRD::get_prefer_raster_effects() {
+ return prefer_raster_effects;
}
static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) {
@@ -80,6 +70,28 @@ RID EffectsRD::_get_uniform_set_from_image(RID p_image) {
return uniform_set;
}
+RID EffectsRD::_get_uniform_set_for_input(RID p_texture) {
+ if (input_to_uniform_set_cache.has(p_texture)) {
+ RID uniform_set = input_to_uniform_set_cache[p_texture];
+ if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ return uniform_set;
+ }
+ }
+
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_INPUT_ATTACHMENT;
+ u.binding = 0;
+ u.ids.push_back(p_texture);
+ uniforms.push_back(u);
+ // This is specific to our subpass shader
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, TONEMAP_MODE_SUBPASS), 0);
+
+ input_to_uniform_set_cache[p_texture] = uniform_set;
+
+ return uniform_set;
+}
+
RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) {
if (texture_to_uniform_set_cache.has(p_texture)) {
RID uniform_set = texture_to_uniform_set_cache[p_texture];
@@ -95,7 +107,7 @@ RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps)
u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler);
u.ids.push_back(p_texture);
uniforms.push_back(u);
- //anything with the same configuration (one texture in binding 0 for set 0), is good
+ // anything with the same configuration (one texture in binding 0 for set 0), is good
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;
@@ -225,6 +237,43 @@ RID EffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1, RID p_te
return uniform_set;
}
+void EffectsRD::fsr_upscale(RID p_source_rd_texture, RID p_secondary_texture, RID p_destination_texture, const Size2i &p_internal_size, const Size2i &p_size, float p_fsr_upscale_sharpness) {
+ memset(&FSR_upscale.push_constant, 0, sizeof(FSRUpscalePushConstant));
+
+ int dispatch_x = (p_size.x + 15) / 16;
+ int dispatch_y = (p_size.y + 15) / 16;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, FSR_upscale.pipeline);
+
+ FSR_upscale.push_constant.resolution_width = p_internal_size.width;
+ FSR_upscale.push_constant.resolution_height = p_internal_size.height;
+ FSR_upscale.push_constant.upscaled_width = p_size.width;
+ FSR_upscale.push_constant.upscaled_height = p_size.height;
+ FSR_upscale.push_constant.sharpness = p_fsr_upscale_sharpness;
+
+ //FSR Easc
+ FSR_upscale.push_constant.pass = FSR_UPSCALE_PASS_EASU;
+ 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_secondary_texture), 1);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &FSR_upscale.push_constant, sizeof(FSRUpscalePushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ //FSR Rcas
+ FSR_upscale.push_constant.pass = FSR_UPSCALE_PASS_RCAS;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_secondary_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_destination_texture), 1);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &FSR_upscale.push_constant, sizeof(FSRUpscalePushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1);
+
+ RD::get_singleton()->compute_list_end(compute_list);
+}
+
void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) {
memset(&copy_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant));
@@ -397,6 +446,8 @@ void EffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i
}
void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the compute version of the gaussian blur with the mobile renderer.");
+
memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
uint32_t base_flags = 0;
@@ -429,7 +480,9 @@ void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back
RD::get_singleton()->compute_list_end();
}
-void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, 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 EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the gaussian glow with the mobile renderer.");
+
memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
CopyMode copy_mode = p_first_pass && p_auto_exposure.is_valid() ? COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : COPY_MODE_GAUSSIAN_GLOW;
@@ -440,7 +493,7 @@ void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const
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_threshold = p_hdr_bleed_threshold;
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
@@ -463,6 +516,57 @@ void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const
RD::get_singleton()->compute_list_end();
}
+void EffectsRD::gaussian_glow_raster(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_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of the gaussian glow with the clustered renderer.");
+
+ memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
+
+ BlurRasterMode blur_mode = p_first_pass && p_auto_exposure.is_valid() ? BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : BLUR_MODE_GAUSSIAN_GLOW;
+ uint32_t base_flags = 0;
+
+ blur_raster.push_constant.pixel_size[0] = p_pixel_size.x;
+ blur_raster.push_constant.pixel_size[1] = p_pixel_size.y;
+
+ blur_raster.push_constant.glow_strength = p_strength;
+ blur_raster.push_constant.glow_bloom = p_bloom;
+ blur_raster.push_constant.glow_hdr_threshold = p_hdr_bleed_threshold;
+ blur_raster.push_constant.glow_hdr_scale = p_hdr_bleed_scale;
+ blur_raster.push_constant.glow_exposure = p_exposure;
+ blur_raster.push_constant.glow_white = 0; //actually unused
+ blur_raster.push_constant.glow_luminance_cap = p_luminance_cap;
+
+ blur_raster.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_raster.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);
+ 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()->draw_list_bind_index_array(draw_list, index_array);
+
+ blur_raster.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_raster.push_constant, sizeof(BlurRasterPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+
+ blur_mode = BLUR_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_raster.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);
+
+ blur_raster.push_constant.flags = base_flags;
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
+
void EffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, 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) {
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
@@ -517,11 +621,10 @@ void EffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, R
if (p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output, p_blur_radius), 1);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_pair(p_metallic, p_normal_roughness), 3);
} else {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_output), 1);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_metallic), 3);
}
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_metallic), 3);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_scale_normal), 2);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1);
@@ -673,7 +776,27 @@ void EffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const S
RD::get_singleton()->compute_list_end();
}
-void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip) {
+void EffectsRD::make_mipmap_raster(RID p_source_rd_texture, RID p_dest_framebuffer, const Size2i &p_size) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of mipmap with the clustered renderer.");
+
+ memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
+
+ BlurRasterMode mode = BLUR_MIPMAP;
+
+ blur_raster.push_constant.pixel_size[0] = 1.0 / float(p_size.x);
+ blur_raster.push_constant.pixel_size[1] = 1.0 / float(p_size.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_raster.pipelines[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_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_raster.push_constant, sizeof(BlurRasterPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
+
+void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip) {
CopyToDPPushConstant push_constant;
push_constant.screen_rect[0] = p_rect.position.x;
push_constant.screen_rect[1] = p_rect.position.y;
@@ -681,7 +804,9 @@ void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffe
push_constant.screen_rect[3] = p_rect.size.height;
push_constant.z_far = p_z_far;
push_constant.z_near = p_z_near;
- push_constant.z_flip = p_dp_flip;
+ push_constant.texel_size[0] = 1.0f / p_dst_size.x;
+ push_constant.texel_size[1] = 1.0f / p_dst_size.y;
+ push_constant.texel_size[0] *= p_dp_flip ? -1.0f : 1.0f; // Encode dp flip as x size sign
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cube_to_dp.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer)));
@@ -724,6 +849,7 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone
tonemap.push_constant.exposure = p_settings.exposure;
tonemap.push_constant.white = p_settings.white;
tonemap.push_constant.auto_exposure_grey = p_settings.auto_exposure_grey;
+ tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier;
tonemap.push_constant.use_color_correction = p_settings.use_color_correction;
@@ -732,8 +858,13 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone
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;
+ if (p_settings.view_count > 1) {
+ // Use MULTIVIEW versions
+ mode += 6;
+ }
+
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_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass()));
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);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.glow_texture, true), 2);
@@ -745,7 +876,49 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone
RD::get_singleton()->draw_list_end();
}
+void EffectsRD::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings) {
+ memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant));
+
+ tonemap.push_constant.use_bcs = p_settings.use_bcs;
+ tonemap.push_constant.bcs[0] = p_settings.brightness;
+ tonemap.push_constant.bcs[1] = p_settings.contrast;
+ tonemap.push_constant.bcs[2] = p_settings.saturation;
+
+ ERR_FAIL_COND_MSG(p_settings.use_glow, "Glow is not supported when using subpasses.");
+ tonemap.push_constant.use_glow = p_settings.use_glow;
+
+ int mode = p_settings.use_1d_color_correction ? TONEMAP_MODE_SUBPASS_1D_LUT : TONEMAP_MODE_SUBPASS;
+ if (p_settings.view_count > 1) {
+ // Use MULTIVIEW versions
+ mode += 6;
+ }
+
+ tonemap.push_constant.tonemapper = p_settings.tonemap_mode;
+ tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure;
+ tonemap.push_constant.exposure = p_settings.exposure;
+ tonemap.push_constant.white = p_settings.white;
+ tonemap.push_constant.auto_exposure_grey = p_settings.auto_exposure_grey;
+
+ tonemap.push_constant.use_color_correction = p_settings.use_color_correction;
+
+ tonemap.push_constant.use_debanding = p_settings.use_debanding;
+ tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier;
+
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_subpass_draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, p_dst_format_id, false, RD::get_singleton()->draw_list_get_current_pass()));
+ RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_for_input(p_source_color), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1); // should be set to a default texture, it's ignored
+ RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.glow_texture, true), 2); // should be set to a default texture, it's ignored
+ RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.color_correction_texture), 3);
+
+ RD::get_singleton()->draw_list_bind_index_array(p_subpass_draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(p_subpass_draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant));
+ RD::get_singleton()->draw_list_draw(p_subpass_draw_list, true);
+}
+
void EffectsRD::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) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of luminance reduction with the mobile renderer.");
+
luminance_reduce.push_constant.source_size[0] = p_source_size.x;
luminance_reduce.push_constant.source_size[1] = p_source_size.y;
luminance_reduce.push_constant.max_luminance = p_max_luminance;
@@ -784,7 +957,41 @@ void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_
RD::get_singleton()->compute_list_end();
}
-void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_halfsize_texture1, RID p_halfsize_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, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
+void EffectsRD::luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster version of luminance reduction with the clustered renderer.");
+ ERR_FAIL_COND_MSG(p_reduce.size() != p_fb.size(), "Incorrect frame buffer account for luminance reduction.");
+
+ luminance_reduce_raster.push_constant.max_luminance = p_max_luminance;
+ luminance_reduce_raster.push_constant.min_luminance = p_min_luminance;
+ luminance_reduce_raster.push_constant.exposure_adjust = p_adjust;
+
+ for (int i = 0; i < p_reduce.size(); i++) {
+ luminance_reduce_raster.push_constant.source_size[0] = i == 0 ? p_source_size.x : luminance_reduce_raster.push_constant.dest_size[0];
+ luminance_reduce_raster.push_constant.source_size[1] = i == 0 ? p_source_size.y : luminance_reduce_raster.push_constant.dest_size[1];
+ luminance_reduce_raster.push_constant.dest_size[0] = MAX(luminance_reduce_raster.push_constant.source_size[0] / 8, 1);
+ luminance_reduce_raster.push_constant.dest_size[1] = MAX(luminance_reduce_raster.push_constant.source_size[1] / 8, 1);
+
+ bool final = !p_set && (luminance_reduce_raster.push_constant.dest_size[0] == 1) && (luminance_reduce_raster.push_constant.dest_size[1] == 1);
+ LuminanceReduceRasterMode mode = final ? LUMINANCE_REDUCE_FRAGMENT_FINAL : (i == 0 ? LUMINANCE_REDUCE_FRAGMENT_FIRST : LUMINANCE_REDUCE_FRAGMENT);
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb[i], 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, luminance_reduce_raster.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_fb[i])));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(i == 0 ? p_source_texture : p_reduce[i - 1]), 0);
+ if (final) {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_prev_luminance), 1);
+ }
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &luminance_reduce_raster.push_constant, sizeof(LuminanceReduceRasterPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+ }
+}
+
+void EffectsRD::bokeh_dof(const BokehBuffers &p_buffers, 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, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of BOKEH DOF with the mobile renderer.");
+
bokeh.push_constant.blur_far_active = p_dof_far;
bokeh.push_constant.blur_far_begin = p_dof_far_begin;
bokeh.push_constant.blur_far_end = p_dof_far_begin + p_dof_far_size;
@@ -811,22 +1018,22 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
// The alpha channel of the source color texture is filled with the expected circle size
// If used for DOF far, the size is positive, if used for near, its negative.
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_GEN_BLUR_SIZE]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_GEN_BLUR_SIZE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_texture), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.depth_texture), 1);
- bokeh.push_constant.size[0] = p_base_texture_size.x;
- bokeh.push_constant.size[1] = p_base_texture_size.y;
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.x;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.y;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
RD::get_singleton()->compute_list_add_barrier(compute_list);
if (p_bokeh_shape == RS::DOF_BOKEH_BOX || p_bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
//second pass
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL]);
static const int quality_samples[4] = { 6, 12, 12, 24 };
@@ -835,18 +1042,18 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
//box and hexagon are more or less the same, and they can work in either half (very low and low quality) or full (medium and high quality_ sizes)
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture1), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.half_texture[0]), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.base_texture), 1);
- bokeh.push_constant.size[0] = p_base_texture_size.x >> 1;
- bokeh.push_constant.size[1] = p_base_texture_size.y >> 1;
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
bokeh.push_constant.half_size = true;
bokeh.push_constant.blur_size *= 0.5;
} else {
//medium and high quality use full size
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_secondary_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.secondary_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.base_texture), 1);
}
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
@@ -858,11 +1065,11 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
bokeh.push_constant.second_pass = true;
if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture2), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture1), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.half_texture[1]), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.half_texture[0]), 1);
} else {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_secondary_texture), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.secondary_texture), 1);
}
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
@@ -873,25 +1080,25 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
//forth pass, upscale for low quality
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_COMPOSITE]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_COMPOSITE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture2), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.half_texture[1]), 1);
- bokeh.push_constant.size[0] = p_base_texture_size.x;
- bokeh.push_constant.size[1] = p_base_texture_size.y;
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.x;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.y;
bokeh.push_constant.half_size = false;
bokeh.push_constant.second_pass = false;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
}
} else {
//circle
//second pass
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_GEN_BOKEH_CIRCULAR]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_GEN_BOKEH_CIRCULAR]);
static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 };
@@ -900,11 +1107,11 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
//circle always runs in half size, otherwise too expensive
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture1), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.half_texture[0]), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.base_texture), 1);
- bokeh.push_constant.size[0] = p_base_texture_size.x >> 1;
- bokeh.push_constant.size[1] = p_base_texture_size.y >> 1;
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
bokeh.push_constant.half_size = true;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
@@ -916,28 +1123,202 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
// upscale
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_COMPOSITE]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_COMPOSITE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture1), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.half_texture[0]), 1);
- bokeh.push_constant.size[0] = p_base_texture_size.x;
- bokeh.push_constant.size[1] = p_base_texture_size.y;
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.x;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.y;
bokeh.push_constant.half_size = false;
bokeh.push_constant.second_pass = false;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
}
RD::get_singleton()->compute_list_end();
}
-void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass) {
- RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, ssao.gather_uniform_set, 0);
+void EffectsRD::bokeh_dof_raster(const BokehBuffers &p_buffers, 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_dof_blur_amount, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use blur DOF with the clustered renderer.");
+
+ memset(&bokeh.push_constant, 0, sizeof(BokehPushConstant));
+
+ bokeh.push_constant.orthogonal = p_cam_orthogonal;
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.width;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.height;
+ bokeh.push_constant.z_far = p_cam_zfar;
+ bokeh.push_constant.z_near = p_cam_znear;
+
+ bokeh.push_constant.second_pass = false;
+ bokeh.push_constant.half_size = false;
+ bokeh.push_constant.blur_size = p_dof_blur_amount;
+
+ if (p_dof_far || p_dof_near) {
+ if (p_dof_far) {
+ bokeh.push_constant.blur_far_active = true;
+ bokeh.push_constant.blur_far_begin = p_dof_far_begin;
+ bokeh.push_constant.blur_far_end = p_dof_far_begin + p_dof_far_size;
+ }
+
+ if (p_dof_near) {
+ bokeh.push_constant.blur_near_active = true;
+ bokeh.push_constant.blur_near_begin = p_dof_near_begin;
+ bokeh.push_constant.blur_near_end = p_dof_near_begin - p_dof_near_size;
+ }
+
+ {
+ // generate our depth data
+ RID framebuffer = p_buffers.base_weight_fb;
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(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, bokeh.raster_pipelines[BOKEH_GEN_BLUR_SIZE].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.depth_texture), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ if (p_bokeh_shape == RS::DOF_BOKEH_BOX || p_bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
+ // double pass approach
+ BokehMode mode = p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL;
+
+ if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
+ //box and hexagon are more or less the same, and they can work in either half (very low and low quality) or full (medium and high quality_ sizes)
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
+ bokeh.push_constant.half_size = true;
+ bokeh.push_constant.blur_size *= 0.5;
+ }
+
+ static const int quality_samples[4] = { 6, 12, 12, 24 };
+ bokeh.push_constant.blur_scale = 0.5;
+ bokeh.push_constant.steps = quality_samples[p_quality];
+
+ RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb;
+
+ // Pass 1
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(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, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.base_texture), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 1);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+
+ // Pass 2
+ if (!bokeh.push_constant.half_size) {
+ // do not output weight, we're writing back into our base buffer
+ mode = p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX_NOWEIGHT : BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT;
+ }
+ bokeh.push_constant.second_pass = true;
+
+ framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[1] : p_buffers.base_fb;
+ RID texture = bokeh.push_constant.half_size ? p_buffers.half_texture[0] : p_buffers.secondary_texture;
+ RID weight = bokeh.push_constant.half_size ? p_buffers.weight_texture[2] : p_buffers.weight_texture[1];
+
+ draw_list = RD::get_singleton()->draw_list_begin(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, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(texture), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(weight), 1);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+
+ if (bokeh.push_constant.half_size) {
+ // Compose pass
+ mode = BOKEH_COMPOSITE;
+ framebuffer = p_buffers.base_fb;
+
+ draw_list = RD::get_singleton()->draw_list_begin(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, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.half_texture[1]), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[3]), 1);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 2);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ } else {
+ // circular is a single pass approach
+ BokehMode mode = BOKEH_GEN_BOKEH_CIRCULAR;
+
+ {
+ // circle always runs in half size, otherwise too expensive (though the code below does support making this optional)
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
+ bokeh.push_constant.half_size = true;
+ // bokeh.push_constant.blur_size *= 0.5;
+ }
+
+ static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 };
+ bokeh.push_constant.blur_scale = quality_scale[p_quality];
+ bokeh.push_constant.steps = 0.0;
+
+ RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb;
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(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, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.base_texture), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 1);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+
+ if (bokeh.push_constant.half_size) {
+ // Compose
+ mode = BOKEH_COMPOSITE;
+ framebuffer = p_buffers.base_fb;
+
+ draw_list = RD::get_singleton()->draw_list_begin(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, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.half_texture[0]), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[2]), 1);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 2);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+ } else {
+ // Just copy it back (we use our blur raster shader here)..
+ draw_list = RD::get_singleton()->draw_list_begin(p_buffers.base_fb, 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_raster.pipelines[BLUR_MODE_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_buffers.base_fb)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.secondary_texture), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+ }
+ }
+ }
+}
+
+void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set) {
+ RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0);
if ((p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) {
- RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, ssao.importance_map_uniform_set, 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_importance_map_uniform_set, 1);
}
for (int i = 0; i < 4; i++) {
@@ -960,7 +1341,7 @@ void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID>
RD::get_singleton()->compute_list_add_barrier(p_compute_list);
}
-void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &p_depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets) {
+void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &p_depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_downsample_uniform_set, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set) {
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->draw_command_begin_label("SSAO");
/* FIRST PASS */
@@ -990,7 +1371,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
u.ids.push_back(p_depth_mipmaps[3]);
uniforms.push_back(u);
}
- ssao.downsample_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.downsample_shader.version_get_shader(ssao.downsample_shader_version, 2), 2);
+ r_downsample_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.downsample_shader.version_get_shader(ssao.downsample_shader_version, 2), 2);
}
float depth_linearize_mul = -p_projection.matrix[3][2];
@@ -1025,7 +1406,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_depth_mipmaps[0]), 1);
if (p_settings.quality > RS::ENV_SSAO_QUALITY_MEDIUM) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ssao.downsample_uniform_set, 2);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, r_downsample_uniform_set, 2);
}
RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.downsample_push_constant, sizeof(SSAODownsamplePushConstant));
@@ -1056,6 +1437,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
ssao.gather_push_constant.half_screen_pixel_size_x025[0] = ssao.gather_push_constant.half_screen_pixel_size[0] * 0.25;
ssao.gather_push_constant.half_screen_pixel_size_x025[1] = ssao.gather_push_constant.half_screen_pixel_size[1] * 0.25;
+ ssao.gather_push_constant.radius = p_settings.radius;
float radius_near_limit = (p_settings.radius * 1.2f);
if (p_settings.quality <= RS::ENV_SSAO_QUALITY_LOW) {
radius_near_limit *= 1.50f;
@@ -1063,12 +1445,8 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) {
ssao.gather_push_constant.radius *= 0.8f;
}
- if (p_settings.half_size) {
- ssao.gather_push_constant.radius *= 0.5f;
- }
}
radius_near_limit /= tan_half_fov_y;
- ssao.gather_push_constant.radius = p_settings.radius;
ssao.gather_push_constant.intensity = p_settings.intensity;
ssao.gather_push_constant.shadow_power = p_settings.power;
ssao.gather_push_constant.shadow_clamp = 0.98;
@@ -1109,7 +1487,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
u.ids.push_back(ssao.gather_constants_buffer);
uniforms.push_back(u);
}
- ssao.gather_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 0), 0);
+ r_gather_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 0), 0);
}
if (p_invalidate_uniform_sets) {
@@ -1136,7 +1514,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
u.ids.push_back(ssao.importance_map_load_counter);
uniforms.push_back(u);
}
- ssao.importance_map_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 2), 1);
+ r_importance_map_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 2), 1);
}
if (p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) {
@@ -1147,7 +1525,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
ssao.importance_map_push_constant.power = p_settings.power;
//base pass
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_BASE]);
- gather_ssao(compute_list, p_ao_pong_slices, p_settings, true);
+ gather_ssao(compute_list, p_ao_pong_slices, p_settings, true, r_gather_uniform_set, RID());
//generate importance map
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GENERATE_IMPORTANCE_MAP]);
@@ -1178,7 +1556,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER]);
}
- gather_ssao(compute_list, p_ao_slices, p_settings, false);
+ gather_ssao(compute_list, p_ao_slices, p_settings, false, r_gather_uniform_set, r_importance_map_uniform_set);
RD::get_singleton()->draw_command_end_label(); // Gather SSAO
}
@@ -1198,8 +1576,9 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) {
if (pass < blur_passes - 2) {
blur_pipeline = SSAO_BLUR_PASS_WIDE;
+ } else {
+ blur_pipeline = SSAO_BLUR_PASS_SMART;
}
- blur_pipeline = SSAO_BLUR_PASS_SMART;
}
for (int i = 0; i < 4; i++) {
@@ -1293,7 +1672,9 @@ void EffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size
RD::get_singleton()->compute_list_end();
}
-void EffectsRD::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 EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap roughness with the mobile renderer.");
+
memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));
roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id;
@@ -1303,10 +1684,10 @@ void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffe
roughness.push_constant.face_size = p_size;
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.pipeline);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.compute_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_framebuffer), 1);
+ 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, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
@@ -1318,11 +1699,37 @@ void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffe
RD::get_singleton()->compute_list_end();
}
+void EffectsRD::cubemap_roughness_raster(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) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap roughness with the clustered renderer.");
+ ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap roughness must process one side at a time.");
+
+ memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));
+
+ roughness.push_constant.face_id = p_face_id;
+ roughness.push_constant.roughness = p_roughness;
+ roughness.push_constant.sample_count = p_sample_count;
+ roughness.push_constant.use_direct_write = p_roughness == 0.0;
+ roughness.push_constant.face_size = p_size;
+
+ 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, roughness.raster_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, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
+
void EffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap downsample with the mobile renderer.");
+
cubemap_downsampler.push_constant.face_size = p_size.x;
+ cubemap_downsampler.push_constant.face_id = 0; // we render all 6 sides to each layer in one call
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.pipeline);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.compute_pipeline);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_cubemap), 1);
@@ -1336,7 +1743,27 @@ void EffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, con
RD::get_singleton()->compute_list_end();
}
+void EffectsRD::cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap downsample with the clustered renderer.");
+ ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap downsample must process one side at a time.");
+
+ cubemap_downsampler.push_constant.face_size = p_size.x;
+ cubemap_downsampler.push_constant.face_id = p_face_id;
+
+ 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, cubemap_downsampler.raster_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_cubemap), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
+
void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap filter with the mobile renderer.");
+
Vector<RD::Uniform> uniforms;
for (int i = 0; i < p_dest_cubemap.size(); i++) {
RD::Uniform u;
@@ -1348,12 +1775,12 @@ void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap,
if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) {
RD::get_singleton()->free(filter.image_uniform_set);
}
- filter.image_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.shader.version_get_shader(filter.shader_version, 0), 2);
+ filter.image_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, 0), 2);
int pipeline = p_use_array ? FILTER_MODE_HIGH_QUALITY_ARRAY : FILTER_MODE_HIGH_QUALITY;
pipeline = filter.use_high_quality ? pipeline : pipeline + 1;
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.pipelines[pipeline]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.compute_pipelines[pipeline]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap, true), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.uniform_set, 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.image_uniform_set, 2);
@@ -1365,55 +1792,42 @@ void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap,
RD::get_singleton()->compute_list_end();
}
-void EffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) {
- SkyPushConstant sky_push_constant;
-
- memset(&sky_push_constant, 0, sizeof(SkyPushConstant));
+void EffectsRD::cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap filter with the clustered renderer.");
+ ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap filter must process one side at a time.");
- sky_push_constant.proj[0] = p_camera.matrix[2][0];
- sky_push_constant.proj[1] = p_camera.matrix[0][0];
- sky_push_constant.proj[2] = p_camera.matrix[2][1];
- sky_push_constant.proj[3] = p_camera.matrix[1][1];
- sky_push_constant.position[0] = p_position.x;
- sky_push_constant.position[1] = p_position.y;
- sky_push_constant.position[2] = p_position.z;
- sky_push_constant.multiplier = p_multiplier;
- sky_push_constant.time = p_time;
- store_transform_3x3(p_orientation, sky_push_constant.orientation);
+ // TODO implement!
+ CubemapFilterRasterPushConstant push_constant;
+ push_constant.mip_level = p_mip_level;
+ push_constant.face_id = p_face_id;
- RenderingDevice::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_fb);
-
- RD::DrawListID draw_list = p_list;
-
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, p_pipeline->get_render_pipeline(RD::INVALID_ID, fb_format));
-
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_samplers, 0);
- if (p_uniform_set.is_valid()) { //material may not have uniform set
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1);
- }
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_fog, 3);
+ CubemapFilterMode mode = filter.use_high_quality ? FILTER_MODE_HIGH_QUALITY : FILTER_MODE_LOW_QUALITY;
+ 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, filter.raster_pipelines[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_source_cubemap), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, filter.uniform_set, 1);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &sky_push_constant, sizeof(SkyPushConstant));
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CubemapFilterRasterPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
}
-void EffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) {
+void EffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) {
ResolvePushConstant push_constant;
push_constant.screen_size[0] = p_screen_size.x;
push_constant.screen_size[1] = p_screen_size.y;
push_constant.samples = p_samples;
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, resolve.pipelines[p_source_giprobe.is_valid() ? RESOLVE_MODE_GI_GIPROBE : RESOLVE_MODE_GI]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, resolve.pipelines[p_source_voxel_gi.is_valid() ? RESOLVE_MODE_GI_VOXEL_GI : RESOLVE_MODE_GI]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_pair(p_source_depth, p_source_normal_roughness), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_dest_depth, p_dest_normal_roughness), 1);
- if (p_source_giprobe.is_valid()) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_giprobe), 2);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_giprobe), 3);
+ if (p_source_voxel_gi.is_valid()) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_voxel_gi), 2);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_voxel_gi), 3);
}
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ResolvePushConstant));
@@ -1423,6 +1837,24 @@ void EffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RI
RD::get_singleton()->compute_list_end(p_barrier);
}
+void EffectsRD::resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) {
+ ResolvePushConstant push_constant;
+ push_constant.screen_size[0] = p_screen_size.x;
+ push_constant.screen_size[1] = p_screen_size.y;
+ push_constant.samples = p_samples;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, resolve.pipelines[RESOLVE_MODE_DEPTH]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_depth), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_depth), 1);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ResolvePushConstant));
+
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.x, p_screen_size.y, 1);
+
+ RD::get_singleton()->compute_list_end(p_barrier);
+}
+
void EffectsRD::sort_buffer(RID p_uniform_set, int p_size) {
Sort::PushConstant push_constant;
push_constant.total_elements = p_size;
@@ -1492,8 +1924,56 @@ void EffectsRD::sort_buffer(RID p_uniform_set, int p_size) {
RD::get_singleton()->compute_list_end();
}
-EffectsRD::EffectsRD() {
- { // Initialize copy
+EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
+ {
+ Vector<String> FSR_upscale_modes;
+
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ // MoltenVK does not support some of the operations used by the normal mode of FSR. Fallback works just fine though.
+ FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n");
+#else
+ // Everyone else can use normal mode when available.
+ if (RD::get_singleton()->get_device_capabilities()->supports_fsr_half_float) {
+ FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_NORMAL\n");
+ } else {
+ FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n");
+ }
+#endif
+
+ FSR_upscale.shader.initialize(FSR_upscale_modes);
+
+ FSR_upscale.shader_version = FSR_upscale.shader.version_create();
+ FSR_upscale.pipeline = RD::get_singleton()->compute_pipeline_create(FSR_upscale.shader.version_get_shader(FSR_upscale.shader_version, 0));
+ }
+
+ prefer_raster_effects = p_prefer_raster_effects;
+
+ if (prefer_raster_effects) {
+ // init blur shader (on compute use copy shader)
+
+ Vector<String> blur_modes;
+ blur_modes.push_back("\n#define MODE_MIPMAP\n"); // BLUR_MIPMAP
+ blur_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); // BLUR_MODE_GAUSSIAN_BLUR
+ blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); // BLUR_MODE_GAUSSIAN_GLOW
+ blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n"); // BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE
+ blur_modes.push_back("\n#define MODE_COPY\n"); // BLUR_MODE_COPY
+
+ blur_raster.shader.initialize(blur_modes);
+ memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
+ blur_raster.shader_version = blur_raster.shader.version_create();
+
+ for (int i = 0; i < BLUR_MODE_MAX; i++) {
+ blur_raster.pipelines[i].setup(blur_raster.shader.version_get_shader(blur_raster.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+
+ } else {
+ // not used in clustered
+ for (int i = 0; i < BLUR_MODE_MAX; i++) {
+ blur_raster.pipelines[i].clear();
+ }
+ }
+
+ if (!prefer_raster_effects) { // 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");
@@ -1511,10 +1991,21 @@ EffectsRD::EffectsRD() {
copy.shader.initialize(copy_modes);
memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
+
+ if (prefer_raster_effects) {
+ // disable shaders we can't use
+ copy.shader.set_variant_enabled(COPY_MODE_GAUSSIAN_COPY, false);
+ copy.shader.set_variant_enabled(COPY_MODE_GAUSSIAN_COPY_8BIT, false);
+ copy.shader.set_variant_enabled(COPY_MODE_GAUSSIAN_GLOW, false);
+ copy.shader.set_variant_enabled(COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE, false);
+ }
+
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));
+ if (copy.shader.is_variant_enabled(i)) {
+ copy.pipelines[i] = RD::get_singleton()->compute_pipeline_create(copy.shader.version_get_shader(copy.shader_version, i));
+ }
}
}
{
@@ -1538,11 +2029,22 @@ EffectsRD::EffectsRD() {
// Initialize roughness
Vector<String> cubemap_roughness_modes;
cubemap_roughness_modes.push_back("");
- roughness.shader.initialize(cubemap_roughness_modes);
- roughness.shader_version = roughness.shader.version_create();
+ if (prefer_raster_effects) {
+ roughness.raster_shader.initialize(cubemap_roughness_modes);
+
+ roughness.shader_version = roughness.raster_shader.version_create();
+
+ roughness.raster_pipeline.setup(roughness.raster_shader.version_get_shader(roughness.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+
+ } else {
+ roughness.compute_shader.initialize(cubemap_roughness_modes);
+
+ roughness.shader_version = roughness.compute_shader.version_create();
- roughness.pipeline = RD::get_singleton()->compute_pipeline_create(roughness.shader.version_get_shader(roughness.shader_version, 0));
+ roughness.compute_pipeline = RD::get_singleton()->compute_pipeline_create(roughness.compute_shader.version_get_shader(roughness.shader_version, 0));
+ roughness.raster_pipeline.clear();
+ }
}
{
@@ -1552,17 +2054,53 @@ EffectsRD::EffectsRD() {
tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n");
tonemap_modes.push_back("\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n");
+ tonemap_modes.push_back("\n#define SUBPASS\n");
+ tonemap_modes.push_back("\n#define SUBPASS\n#define USE_1D_LUT\n");
+
+ // multiview versions of our shaders
+ tonemap_modes.push_back("\n#define MULTIVIEW\n");
+ tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n");
+ tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_1D_LUT\n");
+ tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n");
+ tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n");
+ tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n#define USE_1D_LUT\n");
tonemap.shader.initialize(tonemap_modes);
+ if (!RendererCompositorRD::singleton->is_xr_enabled()) {
+ tonemap.shader.set_variant_enabled(TONEMAP_MODE_NORMAL_MULTIVIEW, false);
+ tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, false);
+ tonemap.shader.set_variant_enabled(TONEMAP_MODE_1D_LUT_MULTIVIEW, false);
+ tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW, false);
+ tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_MULTIVIEW, false);
+ tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW, false);
+ }
+
tonemap.shader_version = tonemap.shader.version_create();
for (int i = 0; i < TONEMAP_MODE_MAX; i++) {
- tonemap.pipelines[i].setup(tonemap.shader.version_get_shader(tonemap.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ if (tonemap.shader.is_variant_enabled(i)) {
+ tonemap.pipelines[i].setup(tonemap.shader.version_get_shader(tonemap.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ } else {
+ tonemap.pipelines[i].clear();
+ }
}
}
- {
+ if (prefer_raster_effects) {
+ Vector<String> luminance_reduce_modes;
+ luminance_reduce_modes.push_back("\n#define FIRST_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FIRST
+ luminance_reduce_modes.push_back("\n"); // LUMINANCE_REDUCE_FRAGMENT
+ luminance_reduce_modes.push_back("\n#define FINAL_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FINAL
+
+ luminance_reduce_raster.shader.initialize(luminance_reduce_modes);
+ memset(&luminance_reduce_raster.push_constant, 0, sizeof(LuminanceReduceRasterPushConstant));
+ luminance_reduce_raster.shader_version = luminance_reduce_raster.shader.version_create();
+
+ for (int i = 0; i < LUMINANCE_REDUCE_FRAGMENT_MAX; i++) {
+ luminance_reduce_raster.pipelines[i].setup(luminance_reduce_raster.shader.version_get_shader(luminance_reduce_raster.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+ } else {
// Initialize luminance_reduce
Vector<String> luminance_reduce_modes;
luminance_reduce_modes.push_back("\n#define READ_TEXTURE\n");
@@ -1576,6 +2114,10 @@ EffectsRD::EffectsRD() {
for (int i = 0; i < LUMINANCE_REDUCE_MAX; i++) {
luminance_reduce.pipelines[i] = RD::get_singleton()->compute_pipeline_create(luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, i));
}
+
+ for (int i = 0; i < LUMINANCE_REDUCE_FRAGMENT_MAX; i++) {
+ luminance_reduce_raster.pipelines[i].clear();
+ }
}
{
@@ -1594,25 +2136,43 @@ EffectsRD::EffectsRD() {
cube_to_dp.pipeline.setup(shader, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), dss, RD::PipelineColorBlendState(), 0);
}
- {
- // Initialize bokeh
- Vector<String> bokeh_modes;
- bokeh_modes.push_back("\n#define MODE_GEN_BLUR_SIZE\n");
- bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n");
- bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n");
- bokeh_modes.push_back("\n#define MODE_BOKEH_CIRCULAR\n");
- bokeh_modes.push_back("\n#define MODE_COMPOSITE_BOKEH\n");
+ // Initialize bokeh
+ Vector<String> bokeh_modes;
+ bokeh_modes.push_back("\n#define MODE_GEN_BLUR_SIZE\n");
+ bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n#define OUTPUT_WEIGHT\n");
+ bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n");
+ bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n#define OUTPUT_WEIGHT\n");
+ bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n");
+ bokeh_modes.push_back("\n#define MODE_BOKEH_CIRCULAR\n#define OUTPUT_WEIGHT\n");
+ bokeh_modes.push_back("\n#define MODE_COMPOSITE_BOKEH\n");
+ if (prefer_raster_effects) {
+ bokeh.raster_shader.initialize(bokeh_modes);
- bokeh.shader.initialize(bokeh_modes);
+ bokeh.shader_version = bokeh.raster_shader.version_create();
- bokeh.shader_version = bokeh.shader.version_create();
+ const int att_count[BOKEH_MAX] = { 1, 2, 1, 2, 1, 2, 1 };
+ for (int i = 0; i < BOKEH_MAX; i++) {
+ RD::PipelineColorBlendState blend_state = (i == BOKEH_COMPOSITE) ? RD::PipelineColorBlendState::create_blend(att_count[i]) : RD::PipelineColorBlendState::create_disabled(att_count[i]);
+ bokeh.raster_pipelines[i].setup(bokeh.raster_shader.version_get_shader(bokeh.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
+ }
+ } else {
+ bokeh.compute_shader.initialize(bokeh_modes);
+ bokeh.compute_shader.set_variant_enabled(BOKEH_GEN_BOKEH_BOX_NOWEIGHT, false);
+ bokeh.compute_shader.set_variant_enabled(BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT, false);
+ bokeh.shader_version = bokeh.compute_shader.version_create();
for (int i = 0; i < BOKEH_MAX; i++) {
- bokeh.pipelines[i] = RD::get_singleton()->compute_pipeline_create(bokeh.shader.version_get_shader(bokeh.shader_version, i));
+ if (bokeh.compute_shader.is_variant_enabled(i)) {
+ bokeh.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(bokeh.compute_shader.version_get_shader(bokeh.shader_version, i));
+ }
+ }
+
+ for (int i = 0; i < BOKEH_MAX; i++) {
+ bokeh.raster_pipelines[i].clear();
}
}
- {
+ if (!prefer_raster_effects) {
// Initialize ssao
RD::SamplerState sampler;
@@ -1668,10 +2228,8 @@ EffectsRD::EffectsRD() {
for (int pass = 0; pass < 4; pass++) {
for (int subPass = 0; subPass < sub_pass_count; subPass++) {
int a = pass;
- int b = subPass;
-
int spmap[5]{ 0, 1, 4, 3, 2 };
- b = spmap[subPass];
+ int b = spmap[subPass];
float ca, sa;
float angle0 = (float(a) + float(b) / float(sub_pass_count)) * Math_PI * 0.5f;
@@ -1756,7 +2314,7 @@ EffectsRD::EffectsRD() {
ERR_FAIL_COND(pipeline != SSAO_MAX);
}
- {
+ if (!prefer_raster_effects) {
// Initialize roughness limiter
Vector<String> shader_modes;
shader_modes.push_back("");
@@ -1772,11 +2330,21 @@ EffectsRD::EffectsRD() {
//Initialize cubemap downsampler
Vector<String> cubemap_downsampler_modes;
cubemap_downsampler_modes.push_back("");
- cubemap_downsampler.shader.initialize(cubemap_downsampler_modes);
- cubemap_downsampler.shader_version = cubemap_downsampler.shader.version_create();
+ if (prefer_raster_effects) {
+ cubemap_downsampler.raster_shader.initialize(cubemap_downsampler_modes);
+
+ cubemap_downsampler.shader_version = cubemap_downsampler.raster_shader.version_create();
- cubemap_downsampler.pipeline = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.shader.version_get_shader(cubemap_downsampler.shader_version, 0));
+ cubemap_downsampler.raster_pipeline.setup(cubemap_downsampler.raster_shader.version_get_shader(cubemap_downsampler.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ } else {
+ cubemap_downsampler.compute_shader.initialize(cubemap_downsampler_modes);
+
+ cubemap_downsampler.shader_version = cubemap_downsampler.compute_shader.version_create();
+
+ cubemap_downsampler.compute_pipeline = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.compute_shader.version_get_shader(cubemap_downsampler.shader_version, 0));
+ cubemap_downsampler.raster_pipeline.clear();
+ }
}
{
@@ -1788,12 +2356,6 @@ EffectsRD::EffectsRD() {
cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n");
cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n#define USE_TEXTURE_ARRAY\n");
cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n#define USE_TEXTURE_ARRAY\n");
- filter.shader.initialize(cubemap_filter_modes);
- filter.shader_version = filter.shader.version_create();
-
- for (int i = 0; i < FILTER_MODE_MAX; i++) {
- filter.pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.shader.version_get_shader(filter.shader_version, i));
- }
if (filter.use_high_quality) {
filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(high_quality_coeffs));
@@ -1803,18 +2365,54 @@ EffectsRD::EffectsRD() {
RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0]);
}
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 0;
- u.ids.push_back(filter.coefficient_buffer);
- uniforms.push_back(u);
+ if (prefer_raster_effects) {
+ filter.raster_shader.initialize(cubemap_filter_modes);
+
+ // array variants are not supported in raster
+ filter.raster_shader.set_variant_enabled(FILTER_MODE_HIGH_QUALITY_ARRAY, false);
+ filter.raster_shader.set_variant_enabled(FILTER_MODE_LOW_QUALITY_ARRAY, false);
+
+ filter.shader_version = filter.raster_shader.version_create();
+
+ for (int i = 0; i < FILTER_MODE_MAX; i++) {
+ if (filter.raster_shader.is_variant_enabled(i)) {
+ filter.raster_pipelines[i].setup(filter.raster_shader.version_get_shader(filter.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ } else {
+ filter.raster_pipelines[i].clear();
+ }
+ }
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(filter.coefficient_buffer);
+ uniforms.push_back(u);
+ }
+ filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.raster_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
+ } else {
+ filter.compute_shader.initialize(cubemap_filter_modes);
+ filter.shader_version = filter.compute_shader.version_create();
+
+ for (int i = 0; i < FILTER_MODE_MAX; i++) {
+ filter.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.compute_shader.version_get_shader(filter.shader_version, i));
+ filter.raster_pipelines[i].clear();
+ }
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(filter.coefficient_buffer);
+ uniforms.push_back(u);
+ }
+ filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
}
- filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
}
- {
+ if (!prefer_raster_effects) {
Vector<String> specular_modes;
specular_modes.push_back("\n#define MODE_MERGE\n");
specular_modes.push_back("\n#define MODE_MERGE\n#define MODE_SSR\n");
@@ -1850,71 +2448,74 @@ EffectsRD::EffectsRD() {
}
}
- {
- Vector<String> ssr_modes;
- ssr_modes.push_back("\n");
- ssr_modes.push_back("\n#define MODE_ROUGH\n");
+ if (!prefer_raster_effects) {
+ {
+ Vector<String> ssr_modes;
+ ssr_modes.push_back("\n");
+ ssr_modes.push_back("\n#define MODE_ROUGH\n");
- ssr.shader.initialize(ssr_modes);
+ ssr.shader.initialize(ssr_modes);
- ssr.shader_version = ssr.shader.version_create();
+ ssr.shader_version = ssr.shader.version_create();
- for (int i = 0; i < SCREEN_SPACE_REFLECTION_MAX; i++) {
- ssr.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssr.shader.version_get_shader(ssr.shader_version, i));
+ for (int i = 0; i < SCREEN_SPACE_REFLECTION_MAX; i++) {
+ ssr.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssr.shader.version_get_shader(ssr.shader_version, i));
+ }
}
- }
- {
- Vector<String> ssr_filter_modes;
- ssr_filter_modes.push_back("\n");
- ssr_filter_modes.push_back("\n#define VERTICAL_PASS\n");
+ {
+ Vector<String> ssr_filter_modes;
+ ssr_filter_modes.push_back("\n");
+ ssr_filter_modes.push_back("\n#define VERTICAL_PASS\n");
- ssr_filter.shader.initialize(ssr_filter_modes);
+ ssr_filter.shader.initialize(ssr_filter_modes);
- ssr_filter.shader_version = ssr_filter.shader.version_create();
+ ssr_filter.shader_version = ssr_filter.shader.version_create();
- for (int i = 0; i < SCREEN_SPACE_REFLECTION_FILTER_MAX; i++) {
- ssr_filter.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssr_filter.shader.version_get_shader(ssr_filter.shader_version, i));
+ for (int i = 0; i < SCREEN_SPACE_REFLECTION_FILTER_MAX; i++) {
+ ssr_filter.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssr_filter.shader.version_get_shader(ssr_filter.shader_version, i));
+ }
}
- }
- {
- Vector<String> ssr_scale_modes;
- ssr_scale_modes.push_back("\n");
+ {
+ Vector<String> ssr_scale_modes;
+ ssr_scale_modes.push_back("\n");
- ssr_scale.shader.initialize(ssr_scale_modes);
+ ssr_scale.shader.initialize(ssr_scale_modes);
- ssr_scale.shader_version = ssr_scale.shader.version_create();
+ ssr_scale.shader_version = ssr_scale.shader.version_create();
- ssr_scale.pipeline = RD::get_singleton()->compute_pipeline_create(ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0));
- }
+ ssr_scale.pipeline = RD::get_singleton()->compute_pipeline_create(ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0));
+ }
- {
- Vector<String> sss_modes;
- sss_modes.push_back("\n#define USE_11_SAMPLES\n");
- sss_modes.push_back("\n#define USE_17_SAMPLES\n");
- sss_modes.push_back("\n#define USE_25_SAMPLES\n");
+ {
+ Vector<String> sss_modes;
+ sss_modes.push_back("\n#define USE_11_SAMPLES\n");
+ sss_modes.push_back("\n#define USE_17_SAMPLES\n");
+ sss_modes.push_back("\n#define USE_25_SAMPLES\n");
- sss.shader.initialize(sss_modes);
+ sss.shader.initialize(sss_modes);
- sss.shader_version = sss.shader.version_create();
+ sss.shader_version = sss.shader.version_create();
- for (int i = 0; i < sss_modes.size(); i++) {
- sss.pipelines[i] = RD::get_singleton()->compute_pipeline_create(sss.shader.version_get_shader(sss.shader_version, i));
+ for (int i = 0; i < sss_modes.size(); i++) {
+ sss.pipelines[i] = RD::get_singleton()->compute_pipeline_create(sss.shader.version_get_shader(sss.shader_version, i));
+ }
}
- }
- {
- Vector<String> resolve_modes;
- resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n");
- resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n#define GIPROBE_RESOLVE\n");
+ {
+ Vector<String> resolve_modes;
+ resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n");
+ resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n#define VOXEL_GI_RESOLVE\n");
+ resolve_modes.push_back("\n#define MODE_RESOLVE_DEPTH\n");
- resolve.shader.initialize(resolve_modes);
+ resolve.shader.initialize(resolve_modes);
- resolve.shader_version = resolve.shader.version_create();
+ resolve.shader_version = resolve.shader.version_create();
- for (int i = 0; i < RESOLVE_MODE_MAX; i++) {
- resolve.pipelines[i] = RD::get_singleton()->compute_pipeline_create(resolve.shader.version_get_shader(resolve.shader_version, i));
+ for (int i = 0; i < RESOLVE_MODE_MAX; i++) {
+ resolve.pipelines[i] = RD::get_singleton()->compute_pipeline_create(resolve.shader.version_get_shader(resolve.shader_version, i));
+ }
}
}
@@ -1980,30 +2581,42 @@ EffectsRD::~EffectsRD() {
RD::get_singleton()->free(index_buffer); //array gets freed as dependency
RD::get_singleton()->free(filter.coefficient_buffer);
- RD::get_singleton()->free(ssao.mirror_sampler);
- RD::get_singleton()->free(ssao.gather_constants_buffer);
- RD::get_singleton()->free(ssao.importance_map_load_counter);
-
- bokeh.shader.version_free(bokeh.shader_version);
- copy.shader.version_free(copy.shader_version);
+ FSR_upscale.shader.version_free(FSR_upscale.shader_version);
+ if (prefer_raster_effects) {
+ blur_raster.shader.version_free(blur_raster.shader_version);
+ bokeh.raster_shader.version_free(blur_raster.shader_version);
+ luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version);
+ roughness.raster_shader.version_free(roughness.shader_version);
+ cubemap_downsampler.raster_shader.version_free(cubemap_downsampler.shader_version);
+ filter.raster_shader.version_free(filter.shader_version);
+ } else {
+ bokeh.compute_shader.version_free(bokeh.shader_version);
+ luminance_reduce.shader.version_free(luminance_reduce.shader_version);
+ roughness.compute_shader.version_free(roughness.shader_version);
+ cubemap_downsampler.compute_shader.version_free(cubemap_downsampler.shader_version);
+ filter.compute_shader.version_free(filter.shader_version);
+ }
+ if (!prefer_raster_effects) {
+ copy.shader.version_free(copy.shader_version);
+ resolve.shader.version_free(resolve.shader_version);
+ specular_merge.shader.version_free(specular_merge.shader_version);
+ ssao.blur_shader.version_free(ssao.blur_shader_version);
+ ssao.gather_shader.version_free(ssao.gather_shader_version);
+ ssao.downsample_shader.version_free(ssao.downsample_shader_version);
+ ssao.interleave_shader.version_free(ssao.interleave_shader_version);
+ ssao.importance_map_shader.version_free(ssao.importance_map_shader_version);
+ roughness_limiter.shader.version_free(roughness_limiter.shader_version);
+ ssr.shader.version_free(ssr.shader_version);
+ ssr_filter.shader.version_free(ssr_filter.shader_version);
+ ssr_scale.shader.version_free(ssr_scale.shader_version);
+ sss.shader.version_free(sss.shader_version);
+
+ RD::get_singleton()->free(ssao.mirror_sampler);
+ RD::get_singleton()->free(ssao.gather_constants_buffer);
+ RD::get_singleton()->free(ssao.importance_map_load_counter);
+ }
copy_to_fb.shader.version_free(copy_to_fb.shader_version);
cube_to_dp.shader.version_free(cube_to_dp.shader_version);
- cubemap_downsampler.shader.version_free(cubemap_downsampler.shader_version);
- filter.shader.version_free(filter.shader_version);
- luminance_reduce.shader.version_free(luminance_reduce.shader_version);
- resolve.shader.version_free(resolve.shader_version);
- roughness.shader.version_free(roughness.shader_version);
- roughness_limiter.shader.version_free(roughness_limiter.shader_version);
sort.shader.version_free(sort.shader_version);
- specular_merge.shader.version_free(specular_merge.shader_version);
- ssao.blur_shader.version_free(ssao.blur_shader_version);
- ssao.gather_shader.version_free(ssao.gather_shader_version);
- ssao.downsample_shader.version_free(ssao.downsample_shader_version);
- ssao.interleave_shader.version_free(ssao.interleave_shader_version);
- ssao.importance_map_shader.version_free(ssao.importance_map_shader_version);
- ssr.shader.version_free(ssr.shader_version);
- ssr_filter.shader.version_free(ssr_filter.shader_version);
- ssr_scale.shader.version_free(ssr_scale.shader_version);
- sss.shader.version_free(sss.shader_version);
tonemap.shader.version_free(tonemap.shader_version);
}
diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h
index 1ba25e301b..6037127e82 100644
--- a/servers/rendering/renderer_rd/effects_rd.h
+++ b/servers/rendering/renderer_rd/effects_rd.h
@@ -33,14 +33,21 @@
#include "core/math/camera_matrix.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
+#include "servers/rendering/renderer_rd/shaders/blur_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/bokeh_dof.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/copy.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/copy_to_fb.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/cube_to_dp.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/cubemap_filter.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/fsr_upscale.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/luminance_reduce.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/resolve.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/roughness_limiter.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl.gen.h"
@@ -55,10 +62,77 @@
#include "servers/rendering/renderer_rd/shaders/ssao_interleave.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/tonemap.glsl.gen.h"
+#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
class EffectsRD {
+private:
+ bool prefer_raster_effects;
+
+ enum FSRUpscalePass {
+ FSR_UPSCALE_PASS_EASU = 0,
+ FSR_UPSCALE_PASS_RCAS = 1
+ };
+
+ struct FSRUpscalePushConstant {
+ float resolution_width;
+ float resolution_height;
+ float upscaled_width;
+ float upscaled_height;
+ float sharpness;
+ int pass;
+ int _unused0, _unused1;
+ };
+
+ struct FSRUpscale {
+ FSRUpscalePushConstant push_constant;
+ FsrUpscaleShaderRD shader;
+ RID shader_version;
+ RID pipeline;
+ } FSR_upscale;
+
+ enum BlurRasterMode {
+ BLUR_MIPMAP,
+
+ BLUR_MODE_GAUSSIAN_BLUR,
+ BLUR_MODE_GAUSSIAN_GLOW,
+ BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE,
+ BLUR_MODE_COPY,
+
+ BLUR_MODE_MAX
+ };
+
+ enum {
+ BLUR_FLAG_HORIZONTAL = (1 << 0),
+ BLUR_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 1),
+ BLUR_FLAG_GLOW_FIRST_PASS = (1 << 2),
+ };
+
+ struct BlurRasterPushConstant {
+ float pixel_size[2];
+ uint32_t flags;
+ uint32_t 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;
+ };
+
+ struct BlurRaster {
+ BlurRasterPushConstant push_constant;
+ BlurRasterShaderRD shader;
+ RID shader_version;
+ PipelineCacheRD pipelines[BLUR_MODE_MAX];
+ } blur_raster;
+
enum CopyMode {
COPY_MODE_GAUSSIAN_COPY,
COPY_MODE_GAUSSIAN_COPY_8BIT,
@@ -160,9 +234,11 @@ class EffectsRD {
struct CubemapRoughness {
CubemapRoughnessPushConstant push_constant;
- CubemapRoughnessShaderRD shader;
+ CubemapRoughnessShaderRD compute_shader;
+ CubemapRoughnessRasterShaderRD raster_shader;
RID shader_version;
- RID pipeline;
+ RID compute_pipeline;
+ PipelineCacheRD raster_pipeline;
} roughness;
enum TonemapMode {
@@ -170,33 +246,43 @@ class EffectsRD {
TONEMAP_MODE_BICUBIC_GLOW_FILTER,
TONEMAP_MODE_1D_LUT,
TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT,
+ TONEMAP_MODE_SUBPASS,
+ TONEMAP_MODE_SUBPASS_1D_LUT,
+
+ TONEMAP_MODE_NORMAL_MULTIVIEW,
+ TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW,
+ TONEMAP_MODE_1D_LUT_MULTIVIEW,
+ TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW,
+ TONEMAP_MODE_SUBPASS_MULTIVIEW,
+ TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW,
+
TONEMAP_MODE_MAX
};
struct TonemapPushConstant {
- float bcs[3];
- uint32_t use_bcs;
+ float bcs[3]; // 12 - 12
+ uint32_t use_bcs; // 4 - 16
- uint32_t use_glow;
- uint32_t use_auto_exposure;
- uint32_t use_color_correction;
- uint32_t tonemapper;
+ uint32_t use_glow; // 4 - 20
+ uint32_t use_auto_exposure; // 4 - 24
+ uint32_t use_color_correction; // 4 - 28
+ uint32_t tonemapper; // 4 - 32
- uint32_t glow_texture_size[2];
- float glow_intensity;
- uint32_t pad3;
+ uint32_t glow_texture_size[2]; // 8 - 40
+ float glow_intensity; // 4 - 44
+ uint32_t pad3; // 4 - 48
- uint32_t glow_mode;
- float glow_levels[7];
+ uint32_t glow_mode; // 4 - 52
+ float glow_levels[7]; // 28 - 80
- float exposure;
- float white;
- float auto_exposure_grey;
- uint32_t pad2;
+ float exposure; // 4 - 84
+ float white; // 4 - 88
+ float auto_exposure_grey; // 4 - 92
+ float luminance_multiplier; // 4 - 96
- float pixel_size[2];
- uint32_t use_fxaa;
- uint32_t use_debanding;
+ float pixel_size[2]; // 8 - 104
+ uint32_t use_fxaa; // 4 - 108
+ uint32_t use_debanding; // 4 - 112
};
/* tonemap actually writes to a framebuffer, which is
@@ -232,11 +318,33 @@ class EffectsRD {
RID pipelines[LUMINANCE_REDUCE_MAX];
} luminance_reduce;
+ enum LuminanceReduceRasterMode {
+ LUMINANCE_REDUCE_FRAGMENT_FIRST,
+ LUMINANCE_REDUCE_FRAGMENT,
+ LUMINANCE_REDUCE_FRAGMENT_FINAL,
+ LUMINANCE_REDUCE_FRAGMENT_MAX
+ };
+
+ struct LuminanceReduceRasterPushConstant {
+ int32_t source_size[2];
+ int32_t dest_size[2];
+ float exposure_adjust;
+ float min_luminance;
+ float max_luminance;
+ uint32_t pad1;
+ };
+
+ struct LuminanceReduceFragment {
+ LuminanceReduceRasterPushConstant push_constant;
+ LuminanceReduceRasterShaderRD shader;
+ RID shader_version;
+ PipelineCacheRD pipelines[LUMINANCE_REDUCE_FRAGMENT_MAX];
+ } luminance_reduce_raster;
+
struct CopyToDPPushConstant {
float z_far;
float z_near;
- uint32_t z_flip;
- uint32_t pad;
+ float texel_size[2];
float screen_rect[4];
};
@@ -274,7 +382,9 @@ class EffectsRD {
enum BokehMode {
BOKEH_GEN_BLUR_SIZE,
BOKEH_GEN_BOKEH_BOX,
+ BOKEH_GEN_BOKEH_BOX_NOWEIGHT,
BOKEH_GEN_BOKEH_HEXAGONAL,
+ BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT,
BOKEH_GEN_BOKEH_CIRCULAR,
BOKEH_COMPOSITE,
BOKEH_MAX
@@ -282,9 +392,11 @@ class EffectsRD {
struct Bokeh {
BokehPushConstant push_constant;
- BokehDofShaderRD shader;
+ BokehDofShaderRD compute_shader;
+ BokehDofRasterShaderRD raster_shader;
RID shader_version;
- RID pipelines[BOKEH_MAX];
+ RID compute_pipelines[BOKEH_MAX];
+ PipelineCacheRD raster_pipelines[BOKEH_MAX];
} bokeh;
enum SSAOMode {
@@ -378,12 +490,10 @@ class EffectsRD {
SSAODownsamplePushConstant downsample_push_constant;
SsaoDownsampleShaderRD downsample_shader;
RID downsample_shader_version;
- RID downsample_uniform_set;
SSAOGatherPushConstant gather_push_constant;
SsaoShaderRD gather_shader;
RID gather_shader_version;
- RID gather_uniform_set;
RID gather_constants_buffer;
bool gather_initialized = false;
@@ -391,7 +501,6 @@ class EffectsRD {
SsaoImportanceMapShaderRD importance_map_shader;
RID importance_map_shader_version;
RID importance_map_load_counter;
- RID importance_map_uniform_set;
RID counter_uniform_set;
SSAOBlurPushConstant blur_push_constant;
@@ -422,15 +531,17 @@ class EffectsRD {
struct CubemapDownsamplerPushConstant {
uint32_t face_size;
- float pad[3];
+ uint32_t face_id;
+ float pad[2];
};
struct CubemapDownsampler {
CubemapDownsamplerPushConstant push_constant;
- CubemapDownsamplerShaderRD shader;
+ CubemapDownsamplerShaderRD compute_shader;
+ CubemapDownsamplerRasterShaderRD raster_shader;
RID shader_version;
- RID pipeline;
-
+ RID compute_pipeline;
+ PipelineCacheRD raster_pipeline;
} cubemap_downsampler;
enum CubemapFilterMode {
@@ -441,10 +552,19 @@ class EffectsRD {
FILTER_MODE_MAX,
};
+ struct CubemapFilterRasterPushConstant {
+ uint32_t mip_level;
+ uint32_t face_id;
+ float pad[2];
+ };
+
struct CubemapFilter {
- CubemapFilterShaderRD shader;
+ CubemapFilterShaderRD compute_shader;
+ CubemapFilterRasterShaderRD raster_shader;
RID shader_version;
- RID pipelines[FILTER_MODE_MAX];
+ RID compute_pipelines[FILTER_MODE_MAX];
+ PipelineCacheRD raster_pipelines[FILTER_MODE_MAX];
+
RID uniform_set;
RID image_uniform_set;
RID coefficient_buffer;
@@ -452,15 +572,6 @@ class EffectsRD {
} filter;
- struct SkyPushConstant {
- float orientation[12];
- float proj[4];
- float position[3];
- float multiplier;
- float time;
- float pad[3];
- };
-
enum SpecularMergeMode {
SPECULAR_MERGE_ADD,
SPECULAR_MERGE_SSR,
@@ -585,7 +696,8 @@ class EffectsRD {
enum ResolveMode {
RESOLVE_MODE_GI,
- RESOLVE_MODE_GI_GIPROBE,
+ RESOLVE_MODE_GI_VOXEL_GI,
+ RESOLVE_MODE_DEPTH,
RESOLVE_MODE_MAX
};
@@ -621,6 +733,7 @@ class EffectsRD {
RID index_array;
Map<RID, RID> texture_to_uniform_set_cache;
+ Map<RID, RID> input_to_uniform_set_cache;
Map<RID, RID> image_to_uniform_set_cache;
@@ -654,6 +767,7 @@ class EffectsRD {
Map<TextureSamplerPair, RID> texture_sampler_to_compute_uniform_set_cache;
RID _get_uniform_set_from_image(RID p_texture);
+ RID _get_uniform_set_for_input(RID p_texture);
RID _get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false);
RID _get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false);
RID _get_compute_uniform_set_from_texture_and_sampler(RID p_texture, RID p_sampler);
@@ -661,6 +775,9 @@ class EffectsRD {
RID _get_compute_uniform_set_from_image_pair(RID p_texture, RID p_texture2);
public:
+ bool get_prefer_raster_effects();
+
+ void fsr_upscale(RID p_source_rd_texture, RID p_secondary_texture, RID p_destination_texture, const Size2i &p_internal_size, const Size2i &p_size, float p_fsr_upscale_sharpness);
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, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID());
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, bool p_alpha_to_one = false);
void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array);
@@ -669,13 +786,37 @@ public:
void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false);
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 set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false);
- void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, 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 gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, 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_threshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
+ void gaussian_glow_raster(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_high_quality = false, 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_threshold = 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 cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
+ void cubemap_roughness_raster(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_dest_texture, const Size2i &p_size);
- void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip);
+ void make_mipmap_raster(RID p_source_rd_texture, RID p_dest_framebuffer, const Size2i &p_size);
+ void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, 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);
+ void luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
+
+ struct BokehBuffers {
+ // bokeh buffers
+
+ // textures
+ Size2i base_texture_size;
+ RID base_texture;
+ RID depth_texture;
+ RID secondary_texture;
+ RID half_texture[2];
+
+ // raster only
+ RID base_fb;
+ RID secondary_fb; // with weights
+ RID half_fb[2]; // with weights
+ RID base_weight_fb;
+ RID weight_texture[4];
+ };
+
+ void bokeh_dof(const BokehBuffers &p_buffers, 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);
+ void bokeh_dof_raster(const BokehBuffers &p_buffers, 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_dof_blur_amount, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
struct TonemapSettings {
bool use_glow = false;
@@ -701,6 +842,7 @@ public:
bool use_auto_exposure = false;
float auto_exposure_grey = 0.5;
RID exposure_texture;
+ float luminance_multiplier = 1.0;
bool use_bcs = false;
float brightness = 1.0;
@@ -714,6 +856,7 @@ public:
bool use_fxaa = false;
bool use_debanding = false;
Vector2i texture_size;
+ uint32_t view_count = 1;
};
struct SSAOSettings {
@@ -737,24 +880,27 @@ public:
};
void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings);
+ void tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings);
- void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass);
- void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets);
+ void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set);
+ void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_downsample_uniform_set, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set);
void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size);
+ void cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size);
void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);
- void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position);
+ void cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level);
void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, 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);
void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection);
void sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const CameraMatrix &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RS::SubSurfaceScatteringQuality p_quality);
- void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL);
+ void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL);
+ void resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL);
void sort_buffer(RID p_uniform_set, int p_size);
- EffectsRD();
+ EffectsRD(bool p_prefer_raster_effects);
~EffectsRD();
};
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 16c6273ff6..03ce2690bf 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -93,8 +93,8 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_specular()
}
}
-void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_giprobe() {
- if (!giprobe_buffer.is_valid()) {
+void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_voxelgi() {
+ if (!voxelgi_buffer.is_valid()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8G8_UINT;
tf.width = width;
@@ -105,41 +105,41 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_giprobe()
RD::TextureFormat tf_aa = tf;
tf_aa.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
tf_aa.samples = texture_samples;
- giprobe_buffer_msaa = RD::get_singleton()->texture_create(tf_aa, RD::TextureView());
+ voxelgi_buffer_msaa = RD::get_singleton()->texture_create(tf_aa, RD::TextureView());
} else {
tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
}
tf.usage_bits |= RD::TEXTURE_USAGE_STORAGE_BIT;
- giprobe_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ voxelgi_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
Vector<RID> fb;
if (msaa != RS::VIEWPORT_MSAA_DISABLED) {
fb.push_back(depth_msaa);
fb.push_back(normal_roughness_buffer_msaa);
- fb.push_back(giprobe_buffer_msaa);
+ fb.push_back(voxelgi_buffer_msaa);
} else {
fb.push_back(depth);
fb.push_back(normal_roughness_buffer);
- fb.push_back(giprobe_buffer);
+ fb.push_back(voxelgi_buffer);
}
- depth_normal_roughness_giprobe_fb = RD::get_singleton()->framebuffer_create(fb);
+ depth_normal_roughness_voxelgi_fb = RD::get_singleton()->framebuffer_create(fb);
}
}
void RenderForwardClustered::RenderBufferDataForwardClustered::clear() {
- if (giprobe_buffer != RID()) {
- RD::get_singleton()->free(giprobe_buffer);
- giprobe_buffer = RID();
+ if (voxelgi_buffer != RID()) {
+ RD::get_singleton()->free(voxelgi_buffer);
+ voxelgi_buffer = RID();
- if (giprobe_buffer_msaa.is_valid()) {
- RD::get_singleton()->free(giprobe_buffer_msaa);
- giprobe_buffer_msaa = RID();
+ if (voxelgi_buffer_msaa.is_valid()) {
+ RD::get_singleton()->free(voxelgi_buffer_msaa);
+ voxelgi_buffer_msaa = RID();
}
- depth_normal_roughness_giprobe_fb = RID();
+ depth_normal_roughness_voxelgi_fb = RID();
}
if (color_msaa.is_valid()) {
@@ -183,9 +183,11 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::clear() {
}
}
-void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) {
+void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) {
clear();
+ ERR_FAIL_COND_MSG(p_view_count != 1, "Multiple views is currently not supported in this renderer, please use the mobile renderer for VR support");
+
msaa = p_msaa;
width = p_width;
@@ -221,7 +223,6 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_c
RD::TEXTURE_SAMPLES_2,
RD::TEXTURE_SAMPLES_4,
RD::TEXTURE_SAMPLES_8,
- RD::TEXTURE_SAMPLES_16
};
texture_samples = ts[p_msaa];
@@ -316,35 +317,57 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
RID prev_pipeline_rd;
RID prev_xforms_uniform_set;
- bool shadow_pass = (p_params->pass_mode == PASS_MODE_SHADOW) || (p_params->pass_mode == PASS_MODE_SHADOW_DP);
+ bool shadow_pass = (p_pass_mode == PASS_MODE_SHADOW) || (p_pass_mode == PASS_MODE_SHADOW_DP);
SceneState::PushConstant push_constant;
- if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) {
+ if (p_pass_mode == PASS_MODE_DEPTH_MATERIAL) {
push_constant.uv_offset = Math::make_half_float(p_params->uv_offset.y) << 16;
push_constant.uv_offset |= Math::make_half_float(p_params->uv_offset.x);
} else {
push_constant.uv_offset = 0;
}
+ bool should_request_redraw = false;
+
for (uint32_t i = p_from_element; i < p_to_element; i++) {
const GeometryInstanceSurfaceDataCache *surf = p_params->elements[i];
const RenderElementInfo &element_info = p_params->element_info[i];
+ if ((p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_SPECULAR) && !(surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) {
+ continue; // Objects with "Depth-prepass" transparency are included in both render lists, but should only be rendered in the transparent pass
+ }
+
+ if (surf->owner->instance_count == 0) {
+ continue;
+ }
+
push_constant.base_index = i + p_params->element_offset;
RID material_uniform_set;
SceneShaderForwardClustered::ShaderData *shader;
void *mesh_surface;
- if (shadow_pass || p_params->pass_mode == PASS_MODE_DEPTH) { //regular depth pass can use these too
+ if (shadow_pass || p_pass_mode == PASS_MODE_DEPTH) { //regular depth pass can use these too
material_uniform_set = surf->material_uniform_set_shadow;
shader = surf->shader_shadow;
mesh_surface = surf->surface_shadow;
} else {
- material_uniform_set = surf->material_uniform_set;
- shader = surf->shader;
+#ifdef DEBUG_ENABLED
+ if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) {
+ material_uniform_set = scene_shader.default_material_uniform_set;
+ shader = scene_shader.default_material_shader_ptr;
+ } else if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW)) {
+ material_uniform_set = scene_shader.overdraw_material_uniform_set;
+ shader = scene_shader.overdraw_material_shader_ptr;
+ } else {
+#endif
+ material_uniform_set = surf->material_uniform_set;
+ shader = surf->shader;
+#ifdef DEBUG_ENABLED
+ }
+#endif
mesh_surface = surf->surface;
}
@@ -352,10 +375,15 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
continue;
}
+ //request a redraw if one of the shaders uses TIME
+ if (shader->uses_time) {
+ should_request_redraw = true;
+ }
+
//find cull variant
SceneShaderForwardClustered::ShaderData::CullVariant cull_variant;
- if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL || p_params->pass_mode == PASS_MODE_SDF || ((p_params->pass_mode == PASS_MODE_SHADOW || p_params->pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) {
+ if (p_pass_mode == PASS_MODE_DEPTH_MATERIAL || p_pass_mode == PASS_MODE_SDF || ((p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) {
cull_variant = SceneShaderForwardClustered::ShaderData::CULL_VARIANT_DOUBLE_SIDED;
} else {
bool mirror = surf->owner->mirror;
@@ -368,50 +396,72 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
RS::PrimitiveType primitive = surf->primitive;
RID xforms_uniform_set = surf->owner->transforms_uniform_set;
- SceneShaderForwardClustered::ShaderVersion shader_version = SceneShaderForwardClustered::SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized.
+ SceneShaderForwardClustered::PipelineVersion pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized.
+
+ uint32_t pipeline_specialization = 0;
+
+ if (p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_TRANSPARENT || p_pass_mode == PASS_MODE_COLOR_SPECULAR) {
+ if (element_info.uses_softshadow) {
+ pipeline_specialization |= SceneShaderForwardClustered::SHADER_SPECIALIZATION_SOFT_SHADOWS;
+ }
+ if (element_info.uses_projector) {
+ pipeline_specialization |= SceneShaderForwardClustered::SHADER_SPECIALIZATION_PROJECTOR;
+ }
+
+ if (p_params->use_directional_soft_shadow) {
+ pipeline_specialization |= SceneShaderForwardClustered::SHADER_SPECIALIZATION_DIRECTIONAL_SOFT_SHADOWS;
+ }
+ }
- switch (p_params->pass_mode) {
- case PASS_MODE_COLOR:
+ switch (p_pass_mode) {
+ case PASS_MODE_COLOR: {
+ if (element_info.uses_lightmap) {
+ pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_LIGHTMAP_OPAQUE_PASS;
+ } else {
+ pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_OPAQUE_PASS;
+ }
+ } break;
case PASS_MODE_COLOR_TRANSPARENT: {
if (element_info.uses_lightmap) {
- shader_version = SceneShaderForwardClustered::SHADER_VERSION_LIGHTMAP_COLOR_PASS;
- } else if (element_info.uses_forward_gi) {
- shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI;
+ pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_LIGHTMAP_TRANSPARENT_PASS;
} else {
- shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS;
+ if (element_info.uses_forward_gi) {
+ pipeline_specialization |= SceneShaderForwardClustered::SHADER_SPECIALIZATION_FORWARD_GI;
+ }
+ pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_TRANSPARENT_PASS;
}
} break;
case PASS_MODE_COLOR_SPECULAR: {
if (element_info.uses_lightmap) {
- shader_version = SceneShaderForwardClustered::SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR;
+ pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_LIGHTMAP_OPAQUE_PASS_WITH_SEPARATE_SPECULAR;
} else {
- shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR;
+ pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_OPAQUE_PASS_WITH_SEPARATE_SPECULAR;
}
} break;
case PASS_MODE_SHADOW:
case PASS_MODE_DEPTH: {
- shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS;
+ pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_DEPTH_PASS;
} break;
case PASS_MODE_SHADOW_DP: {
- shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_DP;
+ pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_DEPTH_PASS_DP;
} break;
case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
- shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS;
+ pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS;
} break;
- case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: {
- shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE;
+ case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI: {
+ pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI;
} break;
case PASS_MODE_DEPTH_MATERIAL: {
- shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
+ pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_DEPTH_PASS_WITH_MATERIAL;
} break;
case PASS_MODE_SDF: {
- shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_SDF;
+ pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_DEPTH_PASS_WITH_SDF;
} break;
}
PipelineCacheRD *pipeline = nullptr;
- pipeline = &shader->pipelines[cull_variant][primitive][shader_version];
+ pipeline = &shader->pipelines[cull_variant][primitive][pipeline_version];
RD::VertexFormatID vertex_format = -1;
RID vertex_array_rd;
@@ -438,7 +488,7 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
prev_index_array_rd = index_array_rd;
}
- RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe);
+ RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe, 0, pipeline_specialization);
if (pipeline_rd != prev_pipeline_rd) {
// checking with prev shader does not make so much sense, as
@@ -453,8 +503,8 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
}
if (material_uniform_set != prev_material_uniform_set) {
- //update uniform set
- if (material_uniform_set.is_valid()) {
+ // Update uniform set.
+ if (material_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material_uniform_set)) { // Material may not have a uniform set.
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET);
}
@@ -471,6 +521,11 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
i += element_info.repeat - 1; //skip equal elements
}
+
+ // Make the actual redraw request
+ if (should_request_redraw) {
+ RenderingServerDefault::redraw_request();
+ }
}
void RenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
@@ -498,8 +553,8 @@ void RenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_lis
case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
_render_list_template<PASS_MODE_DEPTH_NORMAL_ROUGHNESS>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
} break;
- case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: {
- _render_list_template<PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
+ case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI: {
+ _render_list_template<PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
} break;
case PASS_MODE_DEPTH_MATERIAL: {
_render_list_template<PASS_MODE_DEPTH_MATERIAL>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
@@ -559,11 +614,6 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
RendererStorageRD::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel);
RendererStorageRD::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();
-
Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
@@ -729,19 +779,10 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_render_data->environment);
scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_render_data->environment);
- Color ao_color = environment_get_ao_color(p_render_data->environment).to_linear();
- scene_state.ubo.ao_color[0] = ao_color.r;
- scene_state.ubo.ao_color[1] = ao_color.g;
- scene_state.ubo.ao_color[2] = ao_color.b;
- scene_state.ubo.ao_color[3] = ao_color.a;
-
scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_render_data->environment);
scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment);
scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment);
scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment);
- if (scene_state.ubo.fog_height_density >= 0.0001) {
- scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density;
- }
scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment);
Color fog_color = environment_get_fog_light_color(p_render_data->environment).to_linear();
@@ -799,13 +840,16 @@ void RenderForwardClustered::_update_instance_data_buffer(RenderListType p_rende
RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER);
}
}
-void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
+void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, int *p_render_info, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
RenderList *rl = &render_list[p_render_list];
uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size();
scene_state.instance_data[p_render_list].resize(p_offset + element_total);
rl->element_info.resize(p_offset + element_total);
+ if (p_render_info) {
+ p_render_info[RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] += element_total;
+ }
uint32_t repeats = 0;
GeometryInstanceSurfaceDataCache *prev_surface = nullptr;
for (uint32_t i = 0; i < element_total; i++) {
@@ -817,7 +861,7 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, u
if (inst->store_transform_cache) {
RendererStorageRD::store_transform(inst->transform, instance_data.transform);
} else {
- RendererStorageRD::store_transform(Transform(), instance_data.transform);
+ RendererStorageRD::store_transform(Transform3D(), instance_data.transform);
}
instance_data.flags = inst->flags_cache;
@@ -831,7 +875,7 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, u
bool cant_repeat = instance_data.flags & INSTANCE_DATA_FLAG_MULTIMESH || inst->mesh_instance.is_valid();
- if (prev_surface != nullptr && !cant_repeat && prev_surface->sort.sort_key1 == surface->sort.sort_key1 && prev_surface->sort.sort_key2 == surface->sort.sort_key2) {
+ if (prev_surface != nullptr && !cant_repeat && prev_surface->sort.sort_key1 == surface->sort.sort_key1 && prev_surface->sort.sort_key2 == surface->sort.sort_key2 && repeats < RenderElementInfo::MAX_REPEATS) {
//this element is the same as the previous one, count repeats to draw it using instancing
repeats++;
} else {
@@ -841,6 +885,9 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, u
}
}
repeats = 1;
+ if (p_render_info) {
+ p_render_info[RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME]++;
+ }
}
RenderElementInfo &element_info = rl->element_info[p_offset + i];
@@ -848,6 +895,8 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, u
element_info.lod_index = surface->sort.lod_index;
element_info.uses_forward_gi = surface->sort.uses_forward_gi;
element_info.uses_lightmap = surface->sort.uses_lightmap;
+ element_info.uses_softshadow = surface->sort.uses_softshadow;
+ element_info.uses_projector = surface->sort.uses_projector;
if (cant_repeat) {
prev_surface = nullptr;
@@ -867,6 +916,11 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, u
}
}
+_FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primitive, uint32_t p_indices) {
+ static const uint32_t divisor[RS::PRIMITIVE_MAX] = { 1, 2, 1, 3, 1 };
+ static const uint32_t subtractor[RS::PRIMITIVE_MAX] = { 0, 0, 1, 0, 1 };
+ return (p_indices - subtractor[p_primitive]) / divisor[p_primitive];
+}
void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi, bool p_using_opaque_gi, bool p_append) {
if (p_render_list == RENDER_LIST_OPAQUE) {
scene_state.used_sss = false;
@@ -876,7 +930,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
}
uint32_t lightmap_captures_used = 0;
- Plane near_plane(p_render_data->cam_transform.origin, -p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z));
+ Plane near_plane = Plane(-p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z), p_render_data->cam_transform.origin);
near_plane.d += p_render_data->cam_projection.get_z_near();
float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near();
@@ -901,12 +955,28 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
uint32_t flags = inst->base_flags; //fill flags if appropriate
+ if (inst->non_uniform_scale) {
+ flags |= INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE;
+ }
bool uses_lightmap = false;
bool uses_gi = false;
+ float fade_alpha = 1.0;
+
+ if (inst->fade_near || inst->fade_far) {
+ float fade_dist = inst->transform.origin.distance_to(p_render_data->cam_transform.origin);
+ if (inst->fade_far && fade_dist > inst->fade_far_begin) {
+ fade_alpha = MAX(0.0, 1.0 - (fade_dist - inst->fade_far_begin) / (inst->fade_far_end - inst->fade_far_begin));
+ } else if (inst->fade_near && fade_dist < inst->fade_near_end) {
+ fade_alpha = MAX(0.0, (fade_dist - inst->fade_near_begin) / (inst->fade_near_end - inst->fade_near_begin));
+ }
+ }
- if (p_render_list == RENDER_LIST_OPAQUE) {
- //setup GI
+ fade_alpha *= inst->force_alpha * inst->parent_fade_alpha;
+ flags = (flags & ~INSTANCE_DATA_FLAGS_FADE_MASK) | (uint32_t(fade_alpha * 255.0) << INSTANCE_DATA_FLAGS_FADE_SHIFT);
+
+ if (p_render_list == RENDER_LIST_OPAQUE) {
+ // Setup GI
if (inst->lightmap_instance.is_valid()) {
int32_t lightmap_cull_index = -1;
for (uint32_t j = 0; j < scene_state.lightmaps_used; j++) {
@@ -948,14 +1018,14 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS;
}
- if (inst->gi_probes[0].is_valid()) {
+ if (inst->voxel_gi_instances[0].is_valid()) {
uint32_t probe0_index = 0xFFFF;
uint32_t probe1_index = 0xFFFF;
- for (uint32_t j = 0; j < scene_state.giprobes_used; j++) {
- if (scene_state.giprobe_ids[j] == inst->gi_probes[0]) {
+ for (uint32_t j = 0; j < scene_state.voxelgis_used; j++) {
+ if (scene_state.voxelgi_ids[j] == inst->voxel_gi_instances[0]) {
probe0_index = j;
- } else if (scene_state.giprobe_ids[j] == inst->gi_probes[1]) {
+ } else if (scene_state.voxelgi_ids[j] == inst->voxel_gi_instances[1]) {
probe1_index = j;
}
}
@@ -966,7 +1036,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
}
inst->gi_offset_cache = probe0_index | (probe1_index << 16);
- flags |= INSTANCE_DATA_FLAG_USE_GIPROBE;
+ flags |= INSTANCE_DATA_FLAG_USE_VOXEL_GI;
uses_gi = true;
} else {
if (p_using_sdfgi && inst->can_sdfgi) {
@@ -1006,17 +1076,46 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
distance = -distance_max;
}
- surf->sort.lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
+ uint32_t indices;
+ surf->sort.lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, &indices);
+ if (p_render_data->render_info) {
+ indices = _indices_to_primitives(surf->primitive, indices);
+ if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices;
+ } else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices;
+ }
+ }
} else {
surf->sort.lod_index = 0;
+ if (p_render_data->render_info) {
+ uint32_t to_draw = storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ to_draw = _indices_to_primitives(surf->primitive, to_draw);
+ to_draw *= inst->instance_count;
+ if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ } else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ }
+ }
}
// ADD Element
if (p_pass_mode == PASS_MODE_COLOR) {
- if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) {
+#ifdef DEBUG_ENABLED
+ bool force_alpha = unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW);
+#else
+ bool force_alpha = false;
+#endif
+
+ if (fade_alpha < 0.999) {
+ force_alpha = true;
+ }
+
+ if (!force_alpha && (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE))) {
rl->add_element(surf);
}
- if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA) {
+ if (force_alpha || (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA)) {
render_list[RENDER_LIST_ALPHA].add_element(surf);
if (uses_gi) {
surf->sort.uses_forward_gi = 1;
@@ -1061,14 +1160,14 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
}
}
-void RenderForwardClustered::_setup_giprobes(const PagedArray<RID> &p_giprobes) {
- scene_state.giprobes_used = MIN(p_giprobes.size(), uint32_t(MAX_GI_PROBES));
- for (uint32_t i = 0; i < scene_state.giprobes_used; i++) {
- scene_state.giprobe_ids[i] = p_giprobes[i];
+void RenderForwardClustered::_setup_voxelgis(const PagedArray<RID> &p_voxelgis) {
+ scene_state.voxelgis_used = MIN(p_voxelgis.size(), uint32_t(MAX_VOXEL_GI_INSTANCESS));
+ for (uint32_t i = 0; i < scene_state.voxelgis_used; i++) {
+ scene_state.voxelgi_ids[i] = p_voxelgis[i];
}
}
-void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) {
+void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) {
scene_state.lightmaps_used = 0;
for (int i = 0; i < (int)p_lightmaps.size(); i++) {
if (i >= (int)scene_state.max_lightmaps) {
@@ -1091,11 +1190,14 @@ void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps
}
void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) {
+ ERR_FAIL_COND_MSG(p_render_data->view_count != 1, "Multiview is currently not supported in the clustered renderer. Please use the mobile renderer for VR.");
+
RenderBufferDataForwardClustered *render_buffer = nullptr;
if (p_render_data->render_buffers.is_valid()) {
render_buffer = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_data->render_buffers);
}
RendererSceneEnvironmentRD *env = get_environment(p_render_data->environment);
+ static const int texture_multisamples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8 };
//first of all, make a new render pass
//fill up ubo
@@ -1108,6 +1210,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
scene_state.ubo.viewport_size[0] = vp_he.x;
scene_state.ubo.viewport_size[1] = vp_he.y;
scene_state.ubo.directional_light_count = 0;
+ scene_state.ubo.opaque_prepass_threshold = 0.99f;
Size2i screen_size;
RID opaque_framebuffer;
@@ -1120,7 +1223,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
bool using_separate_specular = false;
bool using_ssr = false;
bool using_sdfgi = false;
- bool using_giprobe = false;
+ bool using_voxelgi = false;
bool reverse_cull = false;
if (render_buffer) {
@@ -1129,19 +1232,19 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
opaque_framebuffer = render_buffer->color_fb;
- if (p_render_data->gi_probes->size() > 0) {
- using_giprobe = true;
+ if (p_render_data->voxel_gi_instances->size() > 0) {
+ using_voxelgi = true;
}
- if (!p_render_data->environment.is_valid() && using_giprobe) {
- depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE;
+ if (!p_render_data->environment.is_valid() && using_voxelgi) {
+ depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI;
- } else if (p_render_data->environment.is_valid() && (environment_is_ssr_enabled(p_render_data->environment) || environment_is_sdfgi_enabled(p_render_data->environment) || using_giprobe)) {
+ } else if (p_render_data->environment.is_valid() && (environment_is_ssr_enabled(p_render_data->environment) || environment_is_sdfgi_enabled(p_render_data->environment) || using_voxelgi)) {
if (environment_is_sdfgi_enabled(p_render_data->environment)) {
- depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; // also giprobe
+ depth_pass_mode = using_voxelgi ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; // also voxelgi
using_sdfgi = true;
} else {
- depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS;
+ depth_pass_mode = using_voxelgi ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI : PASS_MODE_DEPTH_NORMAL_ROUGHNESS;
}
if (environment_is_ssr_enabled(p_render_data->environment)) {
@@ -1164,10 +1267,10 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
depth_framebuffer = render_buffer->depth_normal_roughness_fb;
depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0));
} break;
- case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: {
+ case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI: {
_allocate_normal_roughness_texture(render_buffer);
- render_buffer->ensure_giprobe();
- depth_framebuffer = render_buffer->depth_normal_roughness_giprobe_fb;
+ render_buffer->ensure_voxelgi();
+ depth_framebuffer = render_buffer->depth_normal_roughness_voxelgi_fb;
depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0));
depth_pass_clear.push_back(Color(0, 0, 0, 0));
} break;
@@ -1198,15 +1301,15 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_begin_label("Render Setup");
_setup_lightmaps(*p_render_data->lightmaps, p_render_data->cam_transform);
- _setup_giprobes(*p_render_data->gi_probes);
+ _setup_voxelgis(*p_render_data->voxel_gi_instances);
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
_update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
- _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR, using_sdfgi, using_sdfgi || using_giprobe);
+ _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR, using_sdfgi, using_sdfgi || using_voxelgi);
render_list[RENDER_LIST_OPAQUE].sort_by_key();
- render_list[RENDER_LIST_ALPHA].sort_by_depth();
- _fill_instance_data(RENDER_LIST_OPAQUE);
+ render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
+ _fill_instance_data(RENDER_LIST_OPAQUE, p_render_data->render_info ? p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE] : (int *)nullptr);
_fill_instance_data(RENDER_LIST_ALPHA);
RD::get_singleton()->draw_command_end_label();
@@ -1293,7 +1396,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
clear_color = p_default_bg_color;
}
- bool debug_giprobes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION;
+ bool debug_voxelgis = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION;
bool debug_sdfgi_probes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES;
bool depth_pre_pass = depth_framebuffer.is_valid();
@@ -1301,7 +1404,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
bool continue_depth = false;
if (depth_pre_pass) { //depth pre pass
- bool needs_pre_resolve = _needs_post_prepass_render(p_render_data, using_sdfgi || using_giprobe);
+ bool needs_pre_resolve = _needs_post_prepass_render(p_render_data, using_sdfgi || using_voxelgi);
if (needs_pre_resolve) {
RENDER_TIMESTAMP("GI + Render Depth Pre-Pass (parallel)");
} else {
@@ -1312,34 +1415,33 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, depth_pass_clear);
RD::get_singleton()->draw_list_end();
//start compute processes here, so they run at the same time as depth pre-pass
- _post_prepass_render(p_render_data, using_sdfgi || using_giprobe);
+ _post_prepass_render(p_render_data, using_sdfgi || using_voxelgi);
}
RD::get_singleton()->draw_command_begin_label("Render Depth Pre-Pass");
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, nullptr, RID());
- bool finish_depth = using_ssao || using_sdfgi || using_giprobe;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
+ bool finish_depth = using_ssao || using_sdfgi || using_voxelgi;
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, render_buffer == nullptr, p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
_render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear);
RD::get_singleton()->draw_command_end_label();
if (needs_pre_resolve) {
- _pre_resolve_render(p_render_data, using_sdfgi || using_giprobe);
+ _pre_resolve_render(p_render_data, using_sdfgi || using_voxelgi);
}
if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
RENDER_TIMESTAMP("Resolve Depth Pre-Pass");
RD::get_singleton()->draw_command_begin_label("Resolve Depth Pre-Pass");
- if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE) {
+ if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI) {
if (needs_pre_resolve) {
RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, RD::BARRIER_MASK_COMPUTE);
}
- static int texture_samples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8, 16 };
- storage->get_effects()->resolve_gi(render_buffer->depth_msaa, render_buffer->normal_roughness_buffer_msaa, using_giprobe ? render_buffer->giprobe_buffer_msaa : RID(), render_buffer->depth, render_buffer->normal_roughness_buffer, using_giprobe ? render_buffer->giprobe_buffer : RID(), Vector2i(render_buffer->width, render_buffer->height), texture_samples[render_buffer->msaa]);
+ storage->get_effects()->resolve_gi(render_buffer->depth_msaa, render_buffer->normal_roughness_buffer_msaa, using_voxelgi ? render_buffer->voxelgi_buffer_msaa : RID(), render_buffer->depth, render_buffer->normal_roughness_buffer, using_voxelgi ? render_buffer->voxelgi_buffer : RID(), Vector2i(render_buffer->width, render_buffer->height), texture_multisamples[render_buffer->msaa]);
} else if (finish_depth) {
- RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth);
+ storage->get_effects()->resolve_depth(render_buffer->depth_msaa, render_buffer->depth, Vector2i(render_buffer->width, render_buffer->height), texture_multisamples[render_buffer->msaa]);
}
RD::get_singleton()->draw_command_end_label();
}
@@ -1347,11 +1449,12 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
continue_depth = !finish_depth;
}
- _pre_opaque_render(p_render_data, using_ssao, using_sdfgi || using_giprobe, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->giprobe_buffer : RID());
+ _pre_opaque_render(p_render_data, using_ssao, using_sdfgi || using_voxelgi, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->voxelgi_buffer : RID());
RD::get_singleton()->draw_command_begin_label("Render Opaque Pass");
scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
+ scene_state.ubo.opaque_prepass_threshold = 0.0f;
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid());
@@ -1363,8 +1466,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss;
{
- bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes);
- bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes);
+ bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_voxelgis || debug_sdfgi_probes);
+ bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_voxelgis || debug_sdfgi_probes);
//regular forward for now
Vector<Color> c;
@@ -1378,7 +1481,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
_render_list_with_threads(&render_list_params, framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
if (will_continue_color && using_separate_specular) {
// close the specular framebuffer, as it's no longer used
@@ -1389,8 +1492,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_end_label();
- if (debug_giprobes) {
- //debug giprobes
+ if (debug_voxelgis) {
+ //debug voxelgis
bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
@@ -1398,16 +1501,16 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
dc.set_depth_correction(true);
CameraMatrix cm = (dc * p_render_data->cam_projection) * CameraMatrix(p_render_data->cam_transform.affine_inverse());
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
- RD::get_singleton()->draw_command_begin_label("Debug GIProbes");
- for (int i = 0; i < (int)p_render_data->gi_probes->size(); i++) {
- gi.debug_giprobe((*p_render_data->gi_probes)[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0);
+ RD::get_singleton()->draw_command_begin_label("Debug VoxelGIs");
+ for (int i = 0; i < (int)p_render_data->voxel_gi_instances->size(); i++) {
+ gi.debug_voxel_gi((*p_render_data->voxel_gi_instances)[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION, 1.0);
}
RD::get_singleton()->draw_command_end_label();
RD::get_singleton()->draw_list_end();
}
if (debug_sdfgi_probes) {
- //debug giprobes
+ //debug voxelgis
bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
@@ -1431,7 +1534,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
projection = correction * p_render_data->cam_projection;
}
RD::get_singleton()->draw_command_begin_label("Draw Sky");
- sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, projection, p_render_data->cam_transform, time);
+ sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, 1, &projection, p_render_data->cam_transform, time);
RD::get_singleton()->draw_command_end_label();
}
@@ -1443,7 +1546,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
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);
+ storage->get_effects()->resolve_depth(render_buffer->depth_msaa, render_buffer->depth, Vector2i(render_buffer->width, render_buffer->height), texture_multisamples[render_buffer->msaa]);
}
if (using_separate_specular) {
@@ -1466,6 +1569,16 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
}
+ if (scene_state.used_screen_texture) {
+ // Copy screen texture to backbuffer so we can read from it
+ _render_buffers_copy_screen_texture(p_render_data);
+ }
+
+ if (scene_state.used_depth_texture) {
+ // Copy depth texture to backbuffer so we can read from it
+ _render_buffers_copy_depth_texture(p_render_data);
+ }
+
RENDER_TIMESTAMP("Render Transparent Pass");
RD::get_singleton()->draw_command_begin_label("Render Transparent Pass");
@@ -1475,7 +1588,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
{
- RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR_TRANSPARENT, render_buffer == nullptr, p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
_render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
}
@@ -1488,6 +1601,14 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
RD::get_singleton()->draw_command_end_label();
+
+ if (p_render_data->render_buffers.is_valid()) {
+ _debug_draw_cluster(p_render_data->render_buffers);
+
+ RENDER_TIMESTAMP("Tonemap");
+
+ _render_buffers_post_process_and_tonemap(p_render_data);
+ }
}
void RenderForwardClustered::_render_shadow_begin() {
@@ -1498,7 +1619,8 @@ void RenderForwardClustered::_render_shadow_begin() {
render_list[RENDER_LIST_SECONDARY].clear();
scene_state.instance_data[RENDER_LIST_SECONDARY].clear();
}
-void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, 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, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) {
+
+void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &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, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RendererScene::RenderInfo *p_render_info) {
uint32_t shadow_pass_index = scene_state.shadow_passes.size();
SceneState::ShadowPass shadow_pass;
@@ -1513,8 +1635,10 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page
render_data.instances = &p_instances;
render_data.lod_camera_plane = p_camera_plane;
render_data.lod_distance_multiplier = p_lod_distance_multiplier;
+ render_data.render_info = p_render_info;
scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
+ scene_state.ubo.opaque_prepass_threshold = 0.1f;
_setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index);
@@ -1530,7 +1654,7 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, false, false, true);
uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from;
render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size);
- _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size, false);
+ _fill_instance_data(RENDER_LIST_SECONDARY, p_render_info ? p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW] : (int *)nullptr, render_list_from, render_list_size, false);
{
//regular forward for now
@@ -1575,7 +1699,7 @@ void RenderForwardClustered::_render_shadow_end(uint32_t p_barrier) {
for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i];
- RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, true, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
+ RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, true, false, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
_render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect);
}
@@ -1585,7 +1709,7 @@ void RenderForwardClustered::_render_shadow_end(uint32_t p_barrier) {
RD::get_singleton()->draw_command_end_label();
}
-void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) {
+void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) {
RENDER_TIMESTAMP("Setup Render Collider Heightfield");
RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
@@ -1601,6 +1725,7 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
_update_render_base_uniform_set();
scene_state.ubo.dual_paraboloid_side = 0;
+ scene_state.ubo.opaque_prepass_threshold = 0.0;
_setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false);
@@ -1616,13 +1741,13 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
{
//regular forward for now
- RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, true, rp_uniform_set);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, true, false, rp_uniform_set);
_render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ);
}
RD::get_singleton()->draw_command_end_label();
}
-void RenderForwardClustered::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
RENDER_TIMESTAMP("Setup Rendering Material");
RD::get_singleton()->draw_command_begin_label("Render Material");
@@ -1638,6 +1763,7 @@ void RenderForwardClustered::_render_material(const Transform &p_cam_transform,
scene_state.ubo.dual_paraboloid_side = 0;
scene_state.ubo.material_uv2_mode = false;
+ scene_state.ubo.opaque_prepass_threshold = 0.0f;
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
@@ -1651,7 +1777,7 @@ void RenderForwardClustered::_render_material(const Transform &p_cam_transform,
RENDER_TIMESTAMP("Render Material");
{
- RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, false, rp_uniform_set);
//regular forward for now
Vector<Color> clear;
clear.push_back(Color(0, 0, 0, 0));
@@ -1681,6 +1807,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<GeometryInstance *> &p
scene_state.ubo.dual_paraboloid_side = 0;
scene_state.ubo.material_uv2_mode = true;
+ scene_state.ubo.opaque_prepass_threshold = 0.0;
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
@@ -1694,7 +1821,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<GeometryInstance *> &p
RENDER_TIMESTAMP("Render Material");
{
- RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set, true);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, false, rp_uniform_set, true);
//regular forward for now
Vector<Color> clear;
clear.push_back(Color(0, 0, 0, 0));
@@ -1796,7 +1923,7 @@ void RenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i
render_data.cam_projection.set_orthogonal(-h_size, h_size, -v_size, v_size, 0, d_size);
//print_line("pass: " + itos(i) + " cam hsize: " + rtos(h_size) + " vsize: " + rtos(v_size) + " dsize " + rtos(d_size));
- Transform to_bounds;
+ Transform3D to_bounds;
to_bounds.origin = p_bounds.position;
to_bounds.basis.scale(p_bounds.size);
@@ -1812,7 +1939,7 @@ void RenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i
E = sdfgi_framebuffer_size_cache.insert(fb_size, fb);
}
- RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set, false);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, false, rp_uniform_set, false);
_render_list_with_threads(&render_list_params, E->get(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2(), sbs);
}
@@ -1827,7 +1954,9 @@ void RenderForwardClustered::_base_uniforms_changed() {
}
void RenderForwardClustered::_update_render_base_uniform_set() {
- if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version())) {
+ if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version()) || base_uniform_set_updated) {
+ base_uniform_set_updated = false;
+
if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
RD::get_singleton()->free(render_base_uniform_set);
}
@@ -1842,18 +1971,18 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
u.binding = 1;
u.ids.resize(12);
RID *ids_ptr = u.ids.ptrw();
- ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[0] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[1] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[2] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[3] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[4] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[5] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[6] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[7] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[8] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[9] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[10] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[11] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
uniforms.push_back(u);
}
@@ -1868,13 +1997,67 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
{
RD::Uniform u;
u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ RID sampler;
+ switch (decals_get_filter()) {
+ case RS::DECAL_FILTER_NEAREST: {
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR: {
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ }
+
+ u.ids.push_back(sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ RID sampler;
+ switch (light_projectors_get_filter()) {
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ }
+
+ u.ids.push_back(sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_omni_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 4;
+ u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_spot_light_buffer());
uniforms.push_back(u);
@@ -1882,35 +2065,35 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
{
RD::Uniform u;
- u.binding = 5;
+ u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_reflection_probe_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 6;
+ u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.ids.push_back(get_directional_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 7;
+ u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(scene_state.lightmap_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 8;
+ u.binding = 10;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(scene_state.lightmap_capture_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 9;
+ u.binding = 11;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID decal_atlas = storage->decal_atlas_get_texture();
u.ids.push_back(decal_atlas);
@@ -1918,7 +2101,7 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
}
{
RD::Uniform u;
- u.binding = 10;
+ u.binding = 12;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID decal_atlas = storage->decal_atlas_get_texture_srgb();
u.ids.push_back(decal_atlas);
@@ -1926,7 +2109,7 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
}
{
RD::Uniform u;
- u.binding = 11;
+ u.binding = 13;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_decal_buffer());
uniforms.push_back(u);
@@ -1935,7 +2118,7 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 12;
+ u.binding = 14;
u.ids.push_back(storage->global_variables_get_storage_buffer());
uniforms.push_back(u);
}
@@ -1943,7 +2126,7 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 13;
+ u.binding = 15;
u.ids.push_back(sdfgi_get_ubo());
uniforms.push_back(u);
}
@@ -2058,11 +2241,11 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.resize(MAX_GI_PROBES);
+ u.ids.resize(MAX_VOXEL_GI_INSTANCESS);
RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
- for (int i = 0; i < MAX_GI_PROBES; i++) {
- if (p_render_data && i < (int)p_render_data->gi_probes->size()) {
- RID tex = gi.gi_probe_instance_get_texture((*p_render_data->gi_probes)[i]);
+ for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) {
+ if (p_render_data && i < (int)p_render_data->voxel_gi_instances->size()) {
+ RID tex = gi.voxel_gi_instance_get_texture((*p_render_data->voxel_gi_instances)[i]);
if (!tex.is_valid()) {
tex = default_tex;
}
@@ -2088,7 +2271,8 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = (false && rb && rb->depth.is_valid()) ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+ RID dbt = rb ? render_buffers_get_back_depth_texture(p_render_data->render_buffers) : RID();
+ RID texture = (dbt.is_valid()) ? dbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
u.ids.push_back(texture);
uniforms.push_back(u);
}
@@ -2169,7 +2353,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 17;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(rb ? render_buffers_get_gi_probe_buffer(p_render_data->render_buffers) : render_buffers_get_default_gi_probe_buffer());
+ u.ids.push_back(rb ? render_buffers_get_voxel_gi_buffer(p_render_data->render_buffers) : render_buffers_get_default_voxel_gi_buffer());
uniforms.push_back(u);
}
{
@@ -2278,13 +2462,13 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
}
{
- // No GIProbes
+ // No VoxelGIs
RD::Uniform u;
u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.resize(MAX_GI_PROBES);
+ u.ids.resize(MAX_VOXEL_GI_INSTANCESS);
RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
- for (int i = 0; i < MAX_GI_PROBES; i++) {
+ for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) {
u.ids.write[i] = default_tex;
}
@@ -2410,7 +2594,7 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
SceneShaderForwardClustered::MaterialData *material_shadow = nullptr;
void *surface_shadow = nullptr;
- if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
+ if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_position && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
material_shadow = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D);
@@ -2455,12 +2639,14 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
sdcache->sort.sort_key2 = 0;
sdcache->sort.surface_index = p_surface;
- sdcache->sort.material_id_low = p_material_id & 0x3FFF;
- sdcache->sort.material_id_hi = p_material_id >> 14;
+ sdcache->sort.material_id_low = p_material_id & 0xFFFF;
+ sdcache->sort.material_id_hi = p_material_id >> 16;
sdcache->sort.shader_id = p_shader_id;
sdcache->sort.geometry_id = p_mesh.get_local_index(); //only meshes can repeat anyway
sdcache->sort.uses_forward_gi = ginstance->can_sdfgi;
sdcache->sort.priority = p_material->priority;
+ sdcache->sort.uses_projector = ginstance->using_projectors;
+ sdcache->sort.uses_softshadow = ginstance->using_softshadows;
}
void RenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) {
@@ -2552,7 +2738,7 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome
} break;
#if 0
case RS::INSTANCE_IMMEDIATE: {
- RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base);
+ RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.get_or_null(inst->base);
ERR_CONTINUE(!immediate);
_add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass);
@@ -2589,6 +2775,8 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome
//Fill push constant
+ ginstance->base_flags = 0;
+
bool store_transform = true;
if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
@@ -2632,7 +2820,7 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome
ginstance->can_sdfgi = false;
if (!lightmap_instance_is_valid(ginstance->lightmap_instance)) {
- if (ginstance->gi_probes[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) {
+ if (ginstance->voxel_gi_instances[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) {
ginstance->can_sdfgi = true;
}
}
@@ -2719,7 +2907,7 @@ void RenderForwardClustered::geometry_instance_set_mesh_instance(GeometryInstanc
ginstance->mesh_instance = p_mesh_instance;
_geometry_instance_mark_dirty(ginstance);
}
-void RenderForwardClustered::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
+void RenderForwardClustered::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->transform = p_transform;
@@ -2732,6 +2920,7 @@ void RenderForwardClustered::geometry_instance_set_transform(GeometryInstance *p
float max_scale = MAX(model_scale_vec.x, MAX(model_scale_vec.y, model_scale_vec.z));
float min_scale = MIN(model_scale_vec.x, MIN(model_scale_vec.y, model_scale_vec.z));
+
ginstance->non_uniform_scale = max_scale >= 0.0 && (min_scale / max_scale) < 0.9;
ginstance->lod_model_scale = max_scale;
@@ -2741,6 +2930,29 @@ void RenderForwardClustered::geometry_instance_set_lod_bias(GeometryInstance *p_
ERR_FAIL_COND(!ginstance);
ginstance->lod_bias = p_lod_bias;
}
+void RenderForwardClustered::geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->fade_near = p_enable_near;
+ ginstance->fade_near_begin = p_near_begin;
+ ginstance->fade_near_end = p_near_end;
+ ginstance->fade_far = p_enable_far;
+ ginstance->fade_far_begin = p_far_begin;
+ ginstance->fade_far_end = p_far_end;
+}
+
+void RenderForwardClustered::geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->parent_fade_alpha = p_alpha;
+}
+
+void RenderForwardClustered::geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->force_alpha = CLAMP(1.0 - p_transparency, 0, 1);
+}
+
void RenderForwardClustered::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
@@ -2815,7 +3027,7 @@ void RenderForwardClustered::geometry_instance_free(GeometryInstance *p_geometry
}
uint32_t RenderForwardClustered::geometry_instance_get_pair_mask() {
- return (1 << RS::INSTANCE_GI_PROBE);
+ return (1 << RS::INSTANCE_VOXEL_GI);
}
void RenderForwardClustered::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) {
}
@@ -2824,33 +3036,84 @@ void RenderForwardClustered::geometry_instance_pair_reflection_probe_instances(G
void RenderForwardClustered::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) {
}
-Transform RenderForwardClustered::geometry_instance_get_transform(GeometryInstance *p_instance) {
+Transform3D RenderForwardClustered::geometry_instance_get_transform(GeometryInstance *p_instance) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_instance);
- ERR_FAIL_COND_V(!ginstance, Transform());
+ ERR_FAIL_COND_V(!ginstance, Transform3D());
return ginstance->transform;
}
+
AABB RenderForwardClustered::geometry_instance_get_aabb(GeometryInstance *p_instance) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_instance);
ERR_FAIL_COND_V(!ginstance, AABB());
return ginstance->data->aabb;
}
-void RenderForwardClustered::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) {
+void RenderForwardClustered::geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
- if (p_gi_probe_instance_count > 0) {
- ginstance->gi_probes[0] = p_gi_probe_instances[0];
+ if (p_voxel_gi_instance_count > 0) {
+ ginstance->voxel_gi_instances[0] = p_voxel_gi_instances[0];
} else {
- ginstance->gi_probes[0] = RID();
+ ginstance->voxel_gi_instances[0] = RID();
}
- if (p_gi_probe_instance_count > 1) {
- ginstance->gi_probes[1] = p_gi_probe_instances[1];
+ if (p_voxel_gi_instance_count > 1) {
+ ginstance->voxel_gi_instances[1] = p_voxel_gi_instances[1];
} else {
- ginstance->gi_probes[1] = RID();
+ ginstance->voxel_gi_instances[1] = RID();
}
}
+void RenderForwardClustered::geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->using_projectors = p_projector;
+ ginstance->using_softshadows = p_softshadow;
+ _geometry_instance_mark_dirty(ginstance);
+}
+
+void RenderForwardClustered::_update_shader_quality_settings() {
+ Vector<RD::PipelineSpecializationConstant> spec_constants;
+
+ RD::PipelineSpecializationConstant sc;
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
+
+ sc.constant_id = SPEC_CONSTANT_SOFT_SHADOW_SAMPLES;
+ sc.int_value = soft_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES;
+ sc.int_value = penumbra_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES;
+ sc.int_value = directional_soft_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES;
+ sc.int_value = directional_penumbra_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
+ sc.constant_id = SPEC_CONSTANT_DECAL_FILTER;
+ sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_PROJECTOR_FILTER;
+ sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+
+ spec_constants.push_back(sc);
+
+ scene_shader.set_default_specialization_constants(spec_constants);
+
+ _base_uniforms_changed(); //also need this
+}
+
RenderForwardClustered::RenderForwardClustered(RendererStorageRD *p_storage) :
RendererSceneRenderRD(p_storage) {
singleton = this;
@@ -2864,7 +3127,7 @@ RenderForwardClustered::RenderForwardClustered(RendererStorageRD *p_storage) :
defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";
}
defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n";
- defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(get_max_directional_lights()) + "\n";
+ defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n";
{
//lightmaps
@@ -2888,6 +3151,8 @@ RenderForwardClustered::RenderForwardClustered(RendererStorageRD *p_storage) :
}
render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
+
+ _update_shader_quality_settings();
}
RenderForwardClustered::~RenderForwardClustered() {
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index bed3c3b219..d6ab4d1db2 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -51,10 +51,19 @@ class RenderForwardClustered : public RendererSceneRenderRD {
};
enum {
+ SPEC_CONSTANT_SOFT_SHADOW_SAMPLES = 6,
+ SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES = 7,
+ SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES = 8,
+ SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES = 9,
+ SPEC_CONSTANT_DECAL_FILTER = 10,
+ SPEC_CONSTANT_PROJECTOR_FILTER = 11,
+ };
+
+ enum {
SDFGI_MAX_CASCADES = 8,
- MAX_GI_PROBES = 8,
+ MAX_VOXEL_GI_INSTANCESS = 8,
MAX_LIGHTMAPS = 8,
- MAX_GI_PROBES_PER_INSTANCE = 2,
+ MAX_VOXEL_GI_INSTANCESS_PER_INSTANCE = 2,
INSTANCE_DATA_BUFFER_MIN_SIZE = 4096
};
@@ -79,7 +88,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID depth;
RID specular;
RID normal_roughness_buffer;
- RID giprobe_buffer;
+ RID voxelgi_buffer;
RS::ViewportMSAA msaa;
RD::TextureSamples texture_samples;
@@ -89,11 +98,11 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID specular_msaa;
RID normal_roughness_buffer_msaa;
RID roughness_buffer_msaa;
- RID giprobe_buffer_msaa;
+ RID voxelgi_buffer_msaa;
RID depth_fb;
RID depth_normal_roughness_fb;
- RID depth_normal_roughness_giprobe_fb;
+ RID depth_normal_roughness_voxelgi_fb;
RID color_fb;
RID color_specular_fb;
RID specular_only_fb;
@@ -101,14 +110,14 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID render_sdfgi_uniform_set;
void ensure_specular();
- void ensure_giprobe();
+ void ensure_voxelgi();
void clear();
- virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa);
+ virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count);
~RenderBufferDataForwardClustered();
};
- virtual RenderBufferData *_create_render_buffer_data();
+ virtual RenderBufferData *_create_render_buffer_data() override;
void _allocate_normal_roughness_texture(RenderBufferDataForwardClustered *rb);
RID render_base_uniform_set;
@@ -117,9 +126,10 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
- virtual void _base_uniforms_changed();
- virtual RID _render_buffers_get_normal_texture(RID p_render_buffers);
+ virtual void _base_uniforms_changed() override;
+ virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) override;
+ bool base_uniform_set_updated = false;
void _update_render_base_uniform_set();
RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture);
RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0);
@@ -132,7 +142,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
PASS_MODE_SHADOW_DP,
PASS_MODE_DEPTH,
PASS_MODE_DEPTH_NORMAL_ROUGHNESS,
- PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE,
+ PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI,
PASS_MODE_DEPTH_MATERIAL,
PASS_MODE_SDF,
};
@@ -156,8 +166,9 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RD::FramebufferFormatID framebuffer_format = 0;
uint32_t element_offset = 0;
uint32_t barrier = RD::BARRIER_MASK_ALL;
+ bool use_directional_soft_shadow = false;
- RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
+ RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, bool p_use_directional_soft_shadows, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
elements = p_elements;
element_info = p_element_info;
element_count = p_element_count;
@@ -172,6 +183,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
screen_lod_threshold = p_screen_lod_threshold;
element_offset = p_element_offset;
barrier = p_barrier;
+ use_directional_soft_shadow = p_use_directional_soft_shadows;
}
};
@@ -184,19 +196,21 @@ class RenderForwardClustered : public RendererSceneRenderRD {
};
enum {
+ INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5,
INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6,
INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7,
INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8,
INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9,
INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10,
- INSTANCE_DATA_FLAG_USE_GIPROBE = 1 << 11,
+ INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11,
INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15,
INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT = 16,
INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_MASK = 0xFF,
- INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 24,
+ INSTANCE_DATA_FLAGS_FADE_SHIFT = 24,
+ INSTANCE_DATA_FLAGS_FADE_MASK = 0xFF << INSTANCE_DATA_FLAGS_FADE_SHIFT
};
struct SceneState {
@@ -204,7 +218,6 @@ class RenderForwardClustered : public RendererSceneRenderRD {
struct UBO {
float projection_matrix[16];
float inv_projection_matrix[16];
-
float camera_matrix[16];
float inv_camera_matrix[16];
@@ -221,11 +234,6 @@ class RenderForwardClustered : public RendererSceneRenderRD {
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];
float ambient_color_sky_mix;
@@ -250,9 +258,8 @@ class RenderForwardClustered : public RendererSceneRenderRD {
float roughness_limiter_amount;
float roughness_limiter_limit;
- uint32_t roughness_limiter_pad[2];
-
- float ao_color[4];
+ float opaque_prepass_threshold;
+ uint32_t roughness_limiter_pad;
float sdf_to_bounds[16];
@@ -318,8 +325,8 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint32_t max_lightmap_captures;
RID lightmap_capture_buffer;
- RID giprobe_ids[MAX_GI_PROBES];
- uint32_t giprobes_used = 0;
+ RID voxelgi_ids[MAX_VOXEL_GI_INSTANCESS];
+ uint32_t voxelgis_used = 0;
bool used_screen_texture = false;
bool used_normal_texture = false;
@@ -350,11 +357,14 @@ class RenderForwardClustered : public RendererSceneRenderRD {
static RenderForwardClustered *singleton;
void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
- void _setup_giprobes(const PagedArray<RID> &p_giprobes);
- void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform);
+ void _setup_voxelgis(const PagedArray<RID> &p_voxelgis);
+ void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
struct RenderElementInfo {
- uint32_t repeat : 22;
+ enum { MAX_REPEATS = (1 << 20) - 1 };
+ uint32_t repeat : 20;
+ uint32_t uses_projector : 1;
+ uint32_t uses_softshadow : 1;
uint32_t uses_lightmap : 1;
uint32_t uses_forward_gi : 1;
uint32_t lod_index : 8;
@@ -372,7 +382,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint32_t render_list_thread_threshold = 500;
void _update_instance_data_buffer(RenderListType p_render_list);
- void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
+ void _fill_instance_data(RenderListType p_render_list, int *p_render_info = nullptr, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, bool p_append = false);
Map<Size2i, RID> sdfgi_framebuffer_size_cache;
@@ -403,12 +413,14 @@ class RenderForwardClustered : public RendererSceneRenderRD {
union {
struct {
uint64_t lod_index : 8;
- uint64_t surface_index : 10;
+ uint64_t surface_index : 8;
uint64_t geometry_id : 32;
- uint64_t material_id_low : 14;
+ uint64_t material_id_low : 16;
- uint64_t material_id_hi : 18;
+ uint64_t material_id_hi : 16;
uint64_t shader_id : 32;
+ uint64_t uses_softshadow : 1;
+ uint64_t uses_projector : 1;
uint64_t uses_forward_gi : 1;
uint64_t uses_lightmap : 1;
uint64_t depth_layer : 4;
@@ -456,10 +468,21 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint32_t trail_steps = 1;
RID mesh_instance;
bool can_sdfgi = false;
+ bool using_projectors = false;
+ bool using_softshadows = false;
+ bool fade_near = false;
+ float fade_near_begin = 0;
+ float fade_near_end = 0;
+ bool fade_far = false;
+ float fade_far_begin = 0;
+ float fade_far_end = 0;
+ float force_alpha = 1.0;
+ float parent_fade_alpha = 1.0;
+
//used during setup
uint32_t base_flags = 0;
- Transform transform;
- RID gi_probes[MAX_GI_PROBES_PER_INSTANCE];
+ Transform3D transform;
+ RID voxel_gi_instances[MAX_VOXEL_GI_INSTANCESS_PER_INSTANCE];
RID lightmap_instance;
GeometryInstanceLightmapSH *lightmap_sh = nullptr;
GeometryInstanceSurfaceDataCache *surface_caches = nullptr;
@@ -552,7 +575,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
}
};
- void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha
+ void sort_by_reverse_depth_and_priority() { //used for alpha
SortArray<GeometryInstanceSurfaceDataCache *, SortByReverseDepthAndPriority> sorter;
sorter.sort(elements.ptr(), elements.size());
@@ -565,47 +588,59 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RenderList render_list[RENDER_LIST_MAX];
+ virtual void _update_shader_quality_settings() override;
+
protected:
- virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color);
+ virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
- virtual void _render_shadow_begin();
- virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, 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, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true);
- virtual void _render_shadow_process();
- virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL);
+ virtual void _render_shadow_begin() override;
+ virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &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, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RendererScene::RenderInfo *p_render_info = nullptr) override;
+ virtual void _render_shadow_process() override;
+ virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override;
- virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
- virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
- virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture);
- virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances);
+ virtual void _render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
+ virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
+ virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) override;
+ virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) override;
public:
- virtual GeometryInstance *geometry_instance_create(RID p_base);
- virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton);
- virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override);
- virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials);
- virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance);
- virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb);
- virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask);
- virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias);
- virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable);
- virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable);
- virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index);
- virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9);
- virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset);
- virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable);
-
- virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance);
- virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance);
-
- virtual void geometry_instance_free(GeometryInstance *p_geometry_instance);
-
- virtual uint32_t geometry_instance_get_pair_mask();
- virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count);
- virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count);
- virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count);
- virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count);
-
- virtual bool free(RID p_rid);
+ _FORCE_INLINE_ virtual void update_uniform_sets() override {
+ base_uniform_set_updated = true;
+ _update_render_base_uniform_set();
+ }
+
+ virtual GeometryInstance *geometry_instance_create(RID p_base) override;
+ virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override;
+ virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override;
+ virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) override;
+ virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override;
+ virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override;
+ virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) override;
+ virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) override;
+ virtual void geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) override;
+ virtual void geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) override;
+ virtual void geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) override;
+ virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) override;
+ virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) override;
+ virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override;
+ virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) override;
+ virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) override;
+ virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) override;
+
+ virtual Transform3D geometry_instance_get_transform(GeometryInstance *p_instance) override;
+ virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance) override;
+
+ virtual void geometry_instance_free(GeometryInstance *p_geometry_instance) override;
+
+ virtual uint32_t geometry_instance_get_pair_mask() override;
+ virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) override;
+ virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override;
+ virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) override;
+ virtual void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override;
+
+ virtual void geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) override;
+
+ virtual bool free(RID p_rid) override;
RenderForwardClustered(RendererStorageRD *p_storage);
~RenderForwardClustered();
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index f7ed0205af..768bd1de9d 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -30,6 +30,7 @@
#include "scene_shader_forward_clustered.h"
#include "core/config/project_settings.h"
+#include "core/math/math_defs.h"
#include "render_forward_clustered.h"
using namespace RendererSceneRenderImplementation;
@@ -65,6 +66,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
unshaded = false;
uses_vertex = false;
+ uses_position = false;
uses_sss = false;
uses_transmittance = false;
uses_screen_texture = false;
@@ -125,13 +127,13 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection;
actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection;
actions.write_flag_pointers["VERTEX"] = &uses_vertex;
+ actions.write_flag_pointers["POSITION"] = &uses_position;
actions.uniforms = &uniforms;
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = shader_singleton->shader.version_create();
@@ -265,8 +267,26 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j];
- for (int k = 0; k < SHADER_VERSION_MAX; k++) {
- if (!static_cast<SceneShaderForwardClustered *>(singleton)->shader.is_variant_enabled(k)) {
+ for (int k = 0; k < PIPELINE_VERSION_MAX; k++) {
+ ShaderVersion shader_version;
+ static const ShaderVersion shader_version_table[PIPELINE_VERSION_MAX] = {
+ SHADER_VERSION_DEPTH_PASS,
+ SHADER_VERSION_DEPTH_PASS_DP,
+ SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
+ SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI,
+ SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
+ SHADER_VERSION_DEPTH_PASS_WITH_SDF,
+ SHADER_VERSION_COLOR_PASS,
+ SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR,
+ SHADER_VERSION_COLOR_PASS,
+ SHADER_VERSION_LIGHTMAP_COLOR_PASS,
+ SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR,
+ SHADER_VERSION_LIGHTMAP_COLOR_PASS,
+ };
+
+ shader_version = shader_version_table[k];
+
+ if (!static_cast<SceneShaderForwardClustered *>(singleton)->shader.is_variant_enabled(shader_version)) {
continue;
}
RD::PipelineRasterizationState raster_state;
@@ -277,8 +297,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
RD::PipelineMultisampleState multisample_state;
- if (uses_alpha || uses_blend_alpha) {
- // only allow these flags to go through if we have some form of msaa
+ if (k == PIPELINE_VERSION_TRANSPARENT_PASS || k == PIPELINE_VERSION_LIGHTMAP_TRANSPARENT_PASS) {
if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) {
multisample_state.enable_alpha_to_coverage = true;
} else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) {
@@ -286,46 +305,30 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
multisample_state.enable_alpha_to_one = true;
}
- if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
- blend_state = blend_state_blend;
- if (depth_draw == DEPTH_DRAW_OPAQUE) {
- depth_stencil.enable_depth_write = false; //alpha does not draw depth
- }
- } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) {
- if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
- //none, blend state contains nothing
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
- blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
- } else {
- blend_state = blend_state_opaque; //writes to normal and roughness in opaque way
- }
- } else {
- pipelines[i][j][k].clear();
- continue; // do not use this version (will error if using it is attempted)
+ blend_state = blend_state_blend;
+
+ if (depth_draw == DEPTH_DRAW_OPAQUE) {
+ depth_stencil.enable_depth_write = false; //alpha does not draw depth
}
+ } else if (k == PIPELINE_VERSION_OPAQUE_PASS || k == PIPELINE_VERSION_LIGHTMAP_OPAQUE_PASS) {
+ blend_state = blend_state_opaque;
+ } else if (k == PIPELINE_VERSION_DEPTH_PASS || k == PIPELINE_VERSION_DEPTH_PASS_DP) {
+ //none, leave empty
+ } else if (k == PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) {
+ blend_state = blend_state_depth_normal_roughness;
+ } else if (k == PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI) {
+ blend_state = blend_state_depth_normal_roughness_giprobe;
+ } else if (k == PIPELINE_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+ blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+ } else if (k == PIPELINE_VERSION_DEPTH_PASS_WITH_SDF) {
+ blend_state = RD::PipelineColorBlendState(); //no color targets for SDF
} else {
- if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
- blend_state = blend_state_opaque;
- } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
- //none, leave empty
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) {
- blend_state = blend_state_depth_normal_roughness;
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) {
- blend_state = blend_state_depth_normal_roughness_giprobe;
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
- blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) {
- blend_state = RD::PipelineColorBlendState(); //no color targets for SDF
- } else {
- //specular write
- blend_state = blend_state_opaque_specular;
- depth_stencil.enable_depth_test = false;
- depth_stencil.enable_depth_write = false;
- }
+ //specular write
+ blend_state = blend_state_opaque_specular;
}
- RID shader_variant = shader_singleton->shader.version_get_shader(version, k);
- pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0);
+ RID shader_variant = shader_singleton->shader.version_get_shader(version, shader_version);
+ pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0, singleton->default_specialization_constants);
}
}
}
@@ -333,47 +336,56 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
valid = true;
}
-void SceneShaderForwardClustered::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+void SceneShaderForwardClustered::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
- default_texture_params.erase(p_name);
+ if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
+ default_texture_params[p_name].erase(p_index);
+
+ if (default_texture_params[p_name].is_empty()) {
+ default_texture_params.erase(p_name);
+ }
+ }
} else {
- default_texture_params[p_name] = p_texture;
+ if (!default_texture_params.has(p_name)) {
+ default_texture_params[p_name] = Map<int, RID>();
+ }
+ default_texture_params[p_name][p_index] = p_texture;
}
}
void SceneShaderForwardClustered::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
Map<int, StringName> order;
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
continue;
}
- if (E->get().texture_order >= 0) {
- order[E->get().texture_order + 100000] = E->key();
+ if (E.value.texture_order >= 0) {
+ order[E.value.texture_order + 100000] = E.key;
} else {
- order[E->get().order] = E->key();
+ order[E.value.order] = E.key;
}
}
- for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
- pi.name = E->get();
+ for (const KeyValue<int, StringName> &E : order) {
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
+ pi.name = E.value;
p_param_list->push_back(pi);
}
}
void SceneShaderForwardClustered::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
RendererStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E->get());
- p.info.name = E->key(); //supply name
- p.index = E->get().instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+ p.info = ShaderLanguage::uniform_to_property_info(E.value);
+ p.info.name = E.key; //supply name
+ p.index = E.value.instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
p_param_list->push_back(p);
}
}
@@ -398,7 +410,7 @@ Variant SceneShaderForwardClustered::ShaderData::get_default_parameter(const Str
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
return Variant();
}
@@ -409,7 +421,8 @@ RS::ShaderNativeSourceCode SceneShaderForwardClustered::ShaderData::get_native_s
return shader_singleton->shader.version_get_native_source_code(version);
}
-SceneShaderForwardClustered::ShaderData::ShaderData() {
+SceneShaderForwardClustered::ShaderData::ShaderData() :
+ shader_list_element(this) {
valid = false;
uses_screen_texture = false;
}
@@ -425,6 +438,7 @@ SceneShaderForwardClustered::ShaderData::~ShaderData() {
RendererStorageRD::ShaderData *SceneShaderForwardClustered::_create_shader_func() {
ShaderData *shader_data = memnew(ShaderData);
+ singleton->shader_list.add(&shader_data->shader_list_element);
return shader_data;
}
@@ -436,94 +450,14 @@ void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) {
next_pass = p_pass;
}
-void SceneShaderForwardClustered::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+bool SceneShaderForwardClustered::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
- if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
- p_uniform_dirty = true;
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- uniform_buffer = RID();
- }
-
- ubo_data.resize(shader_data->ubo_size);
- if (ubo_data.size()) {
- uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
- memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
- }
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
-
- //check whether buffer changed
- if (p_uniform_dirty && ubo_data.size()) {
- update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
- RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER);
- }
-
- uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
-
- if ((uint32_t)texture_cache.size() != tex_uniform_count) {
- texture_cache.resize(tex_uniform_count);
- p_textures_dirty = true;
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
-
- if (p_textures_dirty && tex_uniform_count) {
- update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true);
- }
-
- if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) {
- // This material does not require an uniform set, so don't create it.
- return;
- }
-
- if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- //no reason to update uniform set, only UBO (or nothing) was needed to update
- return;
- }
-
- Vector<RD::Uniform> uniforms;
-
- {
- if (shader_data->ubo_size) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 0;
- u.ids.push_back(uniform_buffer);
- uniforms.push_back(u);
- }
-
- const RID *textures = texture_cache.ptrw();
- for (uint32_t i = 0; i < tex_uniform_count; i++) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1 + i;
- u.ids.push_back(textures[i]);
- uniforms.push_back(u);
- }
- }
-
- uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, RD::BARRIER_MASK_RASTER);
}
SceneShaderForwardClustered::MaterialData::~MaterialData() {
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- }
-
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- }
+ free_parameters_uniform_set(uniform_set);
}
RendererStorageRD::MaterialData *SceneShaderForwardClustered::_create_material_func(ShaderData *p_shader) {
@@ -545,11 +479,9 @@ SceneShaderForwardClustered::~SceneShaderForwardClustered() {
RD::get_singleton()->free(default_vec4_xform_buffer);
RD::get_singleton()->free(shadow_sampler);
- storage->free(wireframe_material_shader);
storage->free(overdraw_material_shader);
storage->free(default_shader);
- storage->free(wireframe_material);
storage->free(overdraw_material);
storage->free(default_material);
}
@@ -559,17 +491,17 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
{
Vector<String> shader_versions;
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_GIPROBE\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n");
- shader_versions.push_back("");
- shader_versions.push_back("\n#define USE_FORWARD_GI\n");
- shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n");
- shader_versions.push_back("\n#define USE_LIGHTMAP\n");
- shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n");
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_DEPTH_PASS
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); // SHADER_VERSION_DEPTH_PASS_DP
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n"); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_VOXEL_GI\n"); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n"); // SHADER_VERSION_DEPTH_PASS_WITH_SDF
+ shader_versions.push_back(""); // SHADER_VERSION_COLOR_PASS
+ shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n"); // SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR
+ shader_versions.push_back("\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS
+ shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR
+
shader.initialize(shader_versions, p_defines);
}
@@ -608,6 +540,9 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
//builtins
actions.renames["TIME"] = "scene_data.time";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size";
actions.renames["FRAGCOORD"] = "gl_FragCoord";
@@ -628,7 +563,6 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
actions.renames["SSS_STRENGTH"] = "sss_strength";
actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color";
actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth";
- actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve";
actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost";
actions.renames["BACKLIGHT"] = "backlight";
actions.renames["AO"] = "ao";
@@ -651,6 +585,12 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
actions.renames["CUSTOM1"] = "custom1_attrib";
actions.renames["CUSTOM2"] = "custom2_attrib";
actions.renames["CUSTOM3"] = "custom3_attrib";
+ actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+
+ // not implemented but need these just in case code is in the shaders
+ actions.renames["VIEW_INDEX"] = "0";
+ actions.renames["VIEW_MONO_LEFT"] = "0";
+ actions.renames["VIEW_RIGHT"] = "1";
//for light
actions.renames["VIEW"] = "view";
@@ -676,10 +616,10 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
actions.usage_defines["UV2"] = "#define UV2_USED\n";
actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";
actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n";
- actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n";
- actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n";
- actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n";
- actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n";
+ actions.usage_defines["CUSTOM0"] = "#define CUSTOM0_USED\n";
+ actions.usage_defines["CUSTOM1"] = "#define CUSTOM1_USED\n";
+ actions.usage_defines["CUSTOM2"] = "#define CUSTOM2_USED\n";
+ actions.usage_defines["CUSTOM3"] = "#define CUSTOM3_USED\n";
actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP";
actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
@@ -710,6 +650,7 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
actions.render_mode_defines["particle_trails"] = "#define USE_PARTICLE_TRAILS\n";
+ actions.render_mode_defines["depth_draw_opaque"] = "#define USE_OPAQUE_PREPASS\n";
bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley");
@@ -717,7 +658,6 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
}
- actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
@@ -731,6 +671,10 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n";
}
+ actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; // linear filter with mipmaps
+ actions.custom_samplers["DEPTH_TEXTURE"] = "material_samplers[3]";
+ actions.custom_samplers["NORMAL_ROUGHNESS_TEXTURE"] = "material_samplers[1]"; // linear filter
+
actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
@@ -749,7 +693,7 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
actions.global_buffer_array_variable = "global_variables.data";
- actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs";
+ actions.instance_uniform_index_variable = "instances.data[instance_index].instance_uniforms_ofs";
compiler.initialize(actions);
}
@@ -758,7 +702,21 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
//default material and shader
default_shader = storage->shader_allocate();
storage->shader_initialize(default_shader);
- storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n");
+ storage->shader_set_code(default_shader, R"(
+// Default 3D material shader (clustered).
+
+shader_type spatial;
+
+void vertex() {
+ ROUGHNESS = 0.8;
+}
+
+void fragment() {
+ ALBEDO = vec3(0.6);
+ ROUGHNESS = 0.8;
+ METALLIC = 0.2;
+}
+)");
default_material = storage->material_allocate();
storage->material_initialize(default_material);
storage->material_set_shader(default_material, default_shader);
@@ -766,22 +724,34 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS);
default_shader_sdfgi_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF);
+
+ default_material_shader_ptr = md->shader_data;
+ default_material_uniform_set = md->uniform_set;
}
{
overdraw_material_shader = storage->shader_allocate();
storage->shader_initialize(overdraw_material_shader);
- storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }");
+ // Use relatively low opacity so that more "layers" of overlapping objects can be distinguished.
+ storage->shader_set_code(overdraw_material_shader, R"(
+// 3D editor Overdraw debug draw mode shader (clustered).
+
+shader_type spatial;
+
+render_mode blend_add, unshaded;
+
+void fragment() {
+ ALBEDO = vec3(0.4, 0.8, 0.8);
+ ALPHA = 0.1;
+}
+)");
overdraw_material = storage->material_allocate();
storage->material_initialize(overdraw_material);
storage->material_set_shader(overdraw_material, overdraw_material_shader);
- wireframe_material_shader = storage->shader_allocate();
- storage->shader_initialize(wireframe_material_shader);
- storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }");
- wireframe_material = storage->material_allocate();
- storage->material_initialize(wireframe_material);
- storage->material_set_shader(wireframe_material, wireframe_material_shader);
+ MaterialData *md = (MaterialData *)storage->material_get_data(overdraw_material, RendererStorageRD::SHADER_TYPE_3D);
+ overdraw_material_shader_ptr = md->shader_data;
+ overdraw_material_uniform_set = md->uniform_set;
}
{
@@ -804,3 +774,16 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
shadow_sampler = RD::get_singleton()->sampler_create(sampler);
}
}
+
+void SceneShaderForwardClustered::set_default_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_constants) {
+ default_specialization_constants = p_constants;
+ for (SelfList<ShaderData> *E = shader_list.first(); E; E = E->next()) {
+ for (int i = 0; i < ShaderData::CULL_VARIANT_MAX; i++) {
+ for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
+ for (int k = 0; k < SHADER_VERSION_MAX; k++) {
+ E->self()->pipelines[i][j][k].update_specialization_constants(default_specialization_constants);
+ }
+ }
+ }
+ }
+}
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
index 7c8879686b..f2a55939f4 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
@@ -48,17 +48,39 @@ public:
SHADER_VERSION_DEPTH_PASS,
SHADER_VERSION_DEPTH_PASS_DP,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
- SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE,
+ SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI,
SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
SHADER_VERSION_DEPTH_PASS_WITH_SDF,
SHADER_VERSION_COLOR_PASS,
- SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI,
SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR,
SHADER_VERSION_LIGHTMAP_COLOR_PASS,
SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR,
SHADER_VERSION_MAX
};
+ enum PipelineVersion {
+ PIPELINE_VERSION_DEPTH_PASS,
+ PIPELINE_VERSION_DEPTH_PASS_DP,
+ PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
+ PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI,
+ PIPELINE_VERSION_DEPTH_PASS_WITH_MATERIAL,
+ PIPELINE_VERSION_DEPTH_PASS_WITH_SDF,
+ PIPELINE_VERSION_OPAQUE_PASS,
+ PIPELINE_VERSION_OPAQUE_PASS_WITH_SEPARATE_SPECULAR,
+ PIPELINE_VERSION_TRANSPARENT_PASS,
+ PIPELINE_VERSION_LIGHTMAP_OPAQUE_PASS,
+ PIPELINE_VERSION_LIGHTMAP_OPAQUE_PASS_WITH_SEPARATE_SPECULAR,
+ PIPELINE_VERSION_LIGHTMAP_TRANSPARENT_PASS,
+ PIPELINE_VERSION_MAX
+ };
+
+ enum ShaderSpecializations {
+ SHADER_SPECIALIZATION_FORWARD_GI = 1 << 0,
+ SHADER_SPECIALIZATION_PROJECTOR = 1 << 1,
+ SHADER_SPECIALIZATION_SOFT_SHADOWS = 1 << 2,
+ SHADER_SPECIALIZATION_DIRECTIONAL_SOFT_SHADOWS = 1 << 3,
+ };
+
struct ShaderData : public RendererStorageRD::ShaderData {
enum BlendMode { //used internally
BLEND_MODE_MIX,
@@ -102,7 +124,7 @@ public:
bool valid;
RID version;
uint32_t vertex_input_mask;
- PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX];
+ PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_VERSION_MAX];
String path;
@@ -113,7 +135,7 @@ public:
uint32_t ubo_size;
String code;
- Map<StringName, RID> default_texture_params;
+ Map<StringName, Map<int, RID>> default_texture_params;
DepthDraw depth_draw;
DepthTest depth_test;
@@ -130,6 +152,7 @@ public:
bool unshaded;
bool uses_vertex;
+ bool uses_position;
bool uses_sss;
bool uses_transmittance;
bool uses_screen_texture;
@@ -143,7 +166,7 @@ public:
uint32_t index = 0;
virtual void set_code(const String &p_Code);
- virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
@@ -153,10 +176,13 @@ public:
virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+ SelfList<ShaderData> shader_list_element;
ShaderData();
virtual ~ShaderData();
};
+ SelfList<ShaderData>::List shader_list;
+
RendererStorageRD::ShaderData *_create_shader_func();
static RendererStorageRD::ShaderData *_create_shader_funcs() {
return static_cast<SceneShaderForwardClustered *>(singleton)->_create_shader_func();
@@ -165,17 +191,14 @@ public:
struct MaterialData : public RendererStorageRD::MaterialData {
uint64_t last_frame;
ShaderData *shader_data;
- RID uniform_buffer;
RID uniform_set;
- Vector<RID> texture_cache;
- Vector<uint8_t> ubo_data;
uint64_t last_pass = 0;
uint32_t index = 0;
RID next_pass;
uint8_t priority;
virtual void set_render_priority(int p_priority);
virtual void set_next_pass(RID p_pass);
- virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual ~MaterialData();
};
@@ -191,8 +214,6 @@ public:
RID default_material;
RID overdraw_material_shader;
RID overdraw_material;
- RID wireframe_material_shader;
- RID wireframe_material;
RID default_shader_rd;
RID default_shader_sdfgi_rd;
@@ -201,10 +222,18 @@ public:
RID shadow_sampler;
+ RID default_material_uniform_set;
+ ShaderData *default_material_shader_ptr = nullptr;
+
+ RID overdraw_material_uniform_set;
+ ShaderData *overdraw_material_shader_ptr = nullptr;
+
+ Vector<RD::PipelineSpecializationConstant> default_specialization_constants;
SceneShaderForwardClustered();
~SceneShaderForwardClustered();
void init(RendererStorageRD *p_storage, const String p_defines);
+ void set_default_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_constants);
};
} // namespace RendererSceneRenderImplementation
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 4e93fa5333..445623fb86 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -35,6 +35,34 @@
using namespace RendererSceneRenderImplementation;
+RenderForwardMobile::ForwardID RenderForwardMobile::_allocate_forward_id(ForwardIDType p_type) {
+ int32_t index = -1;
+ for (uint32_t i = 0; i < forward_id_allocators[p_type].allocations.size(); i++) {
+ if (forward_id_allocators[p_type].allocations[i] == false) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index == -1) {
+ index = forward_id_allocators[p_type].allocations.size();
+ forward_id_allocators[p_type].allocations.push_back(true);
+ forward_id_allocators[p_type].map.push_back(0xFF);
+ } else {
+ forward_id_allocators[p_type].allocations[index] = true;
+ }
+
+ return index;
+}
+void RenderForwardMobile::_free_forward_id(ForwardIDType p_type, ForwardID p_id) {
+ ERR_FAIL_INDEX(p_id, (ForwardID)forward_id_allocators[p_type].allocations.size());
+ forward_id_allocators[p_type].allocations[p_id] = false;
+}
+
+void RenderForwardMobile::_map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) {
+ forward_id_allocators[p_type].map[p_id] = p_index;
+}
+
/* Render buffer */
void RenderForwardMobile::RenderBufferDataForwardMobile::clear() {
@@ -50,34 +78,80 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::clear() {
color = RID();
depth = RID();
- color_fb = RID();
+ for (int i = 0; i < FB_CONFIG_MAX; i++) {
+ color_fbs[i] = RID();
+ }
}
-void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) {
+void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) {
clear();
msaa = p_msaa;
+ Size2i target_size = RD::get_singleton()->texture_size(p_target_buffer);
+
width = p_width;
height = p_height;
+ bool is_scaled = (target_size.width != p_width) || (target_size.height != p_height);
+ view_count = p_view_count;
color = p_color_buffer;
depth = p_depth_buffer;
- // re-introduce setting up msaa? For now we ignore this...
+ // We are creating 4 configurations here for our framebuffers.
if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) {
Vector<RID> fb;
- fb.push_back(p_color_buffer);
- fb.push_back(depth);
+ fb.push_back(p_color_buffer); // 0 - color buffer
+ fb.push_back(depth); // 1 - depth buffer
+
+ // Now define our subpasses
+ Vector<RD::FramebufferPass> passes;
+ RD::FramebufferPass pass;
+
+ // re-using the same attachments
+ pass.color_attachments.push_back(0);
+ pass.depth_attachment = 1;
- color_fb = RD::get_singleton()->framebuffer_create(fb);
+ // - opaque pass
+ passes.push_back(pass);
+ color_fbs[FB_CONFIG_ONE_PASS] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
+
+ // - add sky pass
+ passes.push_back(pass);
+ color_fbs[FB_CONFIG_TWO_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
+
+ // - add alpha pass
+ passes.push_back(pass);
+ color_fbs[FB_CONFIG_THREE_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
+
+ if (!is_scaled) {
+ // - add blit to 2D pass
+ fb.push_back(p_target_buffer); // 2 - target buffer
+
+ RD::FramebufferPass blit_pass;
+ blit_pass.color_attachments.push_back(2);
+ blit_pass.input_attachments.push_back(0);
+ passes.push_back(blit_pass);
+
+ color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
+ } else {
+ // can't do our blit pass if resolutions don't match
+ color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RID();
+ }
} else {
+ RD::DataFormat color_format = RenderForwardMobile::singleton->_render_buffers_get_color_format();
+
RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ if (view_count > 1) {
+ tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ } else {
+ tf.texture_type = RD::TEXTURE_TYPE_2D;
+ }
+ tf.format = color_format;
tf.width = p_width;
tf.height = p_height;
- tf.texture_type = RD::TEXTURE_TYPE_2D;
+ tf.array_layers = view_count; // create a layer for every view
tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = {
@@ -85,7 +159,6 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b
RD::TEXTURE_SAMPLES_2,
RD::TEXTURE_SAMPLES_4,
RD::TEXTURE_SAMPLES_8,
- RD::TEXTURE_SAMPLES_16
};
texture_samples = ts[p_msaa];
@@ -100,14 +173,87 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b
{
Vector<RID> fb;
- fb.push_back(color_msaa);
- fb.push_back(depth_msaa);
+ fb.push_back(color_msaa); // 0 - msaa color buffer
+ fb.push_back(depth_msaa); // 1 - msaa depth buffer
+
+ // Now define our subpasses
+ Vector<RD::FramebufferPass> passes;
+ RD::FramebufferPass pass;
+
+ // re-using the same attachments
+ pass.color_attachments.push_back(0);
+ pass.depth_attachment = 1;
+
+ // - opaque pass
+ passes.push_back(pass);
+
+ // - add sky pass
+ fb.push_back(color); // 2 - color buffer
+ passes.push_back(pass); // without resolve for our 3 + 4 subpass config
+ {
+ // but with resolve for our 2 subpass config
+ Vector<RD::FramebufferPass> two_passes;
+ two_passes.push_back(pass); // opaque subpass without resolve
+ pass.resolve_attachments.push_back(2);
+ two_passes.push_back(pass); // sky subpass with resolve
+
+ color_fbs[FB_CONFIG_TWO_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, two_passes, RenderingDevice::INVALID_ID, view_count);
+ }
+
+ // - add alpha pass (with resolve, we just added that above)
+ passes.push_back(pass);
+ color_fbs[FB_CONFIG_THREE_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
- color_fb = RD::get_singleton()->framebuffer_create(fb);
+ {
+ // we also need our one pass with resolve
+ Vector<RD::FramebufferPass> one_pass_with_resolve;
+ one_pass_with_resolve.push_back(pass); // note our pass configuration already has resolve..
+ color_fbs[FB_CONFIG_ONE_PASS] = RD::get_singleton()->framebuffer_create_multipass(fb, one_pass_with_resolve, RenderingDevice::INVALID_ID, view_count);
+ }
+
+ if (!is_scaled) {
+ // - add blit to 2D pass
+ fb.push_back(p_target_buffer); // 3 - target buffer
+ RD::FramebufferPass blit_pass;
+ blit_pass.color_attachments.push_back(3);
+ blit_pass.input_attachments.push_back(2);
+ passes.push_back(blit_pass);
+
+ color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
+ } else {
+ // can't do our blit pass if resolutions don't match
+ color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RID();
+ }
}
}
}
+RID RenderForwardMobile::reflection_probe_create_framebuffer(RID p_color, RID p_depth) {
+ // Our attachments
+ Vector<RID> fb;
+ fb.push_back(p_color); // 0
+ fb.push_back(p_depth); // 1
+
+ // Now define our subpasses
+ Vector<RD::FramebufferPass> passes;
+ RD::FramebufferPass pass;
+
+ // re-using the same attachments
+ pass.color_attachments.push_back(0);
+ pass.depth_attachment = 1;
+
+ // - opaque pass
+ passes.push_back(pass);
+
+ // - sky pass
+ passes.push_back(pass);
+
+ // - alpha pass
+ passes.push_back(pass);
+
+ return RD::get_singleton()->framebuffer_create_multipass(fb, passes);
+}
+
RenderForwardMobile::RenderBufferDataForwardMobile::~RenderBufferDataForwardMobile() {
clear();
}
@@ -125,6 +271,23 @@ bool RenderForwardMobile::free(RID p_rid) {
/* Render functions */
+float RenderForwardMobile::_render_buffers_get_luminance_multiplier() {
+ // On mobile renderer we need to multiply source colors by 2 due to using a UNORM buffer
+ // and multiplying by the output color during 3D rendering by 0.5
+ return 2.0;
+}
+
+RD::DataFormat RenderForwardMobile::_render_buffers_get_color_format() {
+ // Using 32bit buffers enables AFBC on mobile devices which should have a definite performance improvement (MALI G710 and newer support this on 64bit RTs)
+ return RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
+}
+
+bool RenderForwardMobile::_render_buffers_can_be_storage() {
+ // Using 32bit buffers enables AFBC on mobile devices which should have a definite performance improvement (MALI G710 and newer support this on 64bit RTs)
+ // Doesn't support storage
+ return false;
+}
+
RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas, int p_index) {
//there should always be enough uniform buffers for render passes, otherwise bugs
ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID());
@@ -226,11 +389,11 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
RD::Uniform u;
u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.resize(MAX_GI_PROBES);
+ u.ids.resize(MAX_VOXEL_GI_INSTANCESS);
RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
- for (int i = 0; i < MAX_GI_PROBES; i++) {
- if (i < (int)p_gi_probes.size()) {
- RID tex = gi.gi_probe_instance_get_texture(p_gi_probes[i]);
+ for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) {
+ if (i < (int)p_voxel_gi_instances.size()) {
+ RID tex = gi.voxel_gi_instance_get_texture(p_voxel_gi_instances[i]);
if (!tex.is_valid()) {
tex = default_tex;
}
@@ -257,7 +420,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
RD::Uniform u;
u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = (false && rb && rb->depth.is_valid()) ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+ RID dbt = rb ? render_buffers_get_back_depth_texture(p_render_data->render_buffers) : RID();
+ RID texture = (dbt.is_valid()) ? dbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
u.ids.push_back(texture);
uniforms.push_back(u);
}
@@ -283,7 +447,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
return render_pass_uniform_sets[p_index];
}
-void RenderForwardMobile::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) {
+void RenderForwardMobile::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) {
// This probably needs to change...
scene_state.lightmaps_used = 0;
for (int i = 0; i < (int)p_lightmaps.size(); i++) {
@@ -319,30 +483,71 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
scene_state.ubo.viewport_size[0] = vp_he.x;
scene_state.ubo.viewport_size[1] = vp_he.y;
scene_state.ubo.directional_light_count = 0;
+ scene_state.ubo.opaque_prepass_threshold = 0.0;
+
+ // We can only use our full subpass approach if we're:
+ // - not reading from SCREEN_TEXTURE/DEPTH_TEXTURE
+ // - not using ssr/sss (currently not supported)
+ // - not using glow or other post effects (can't do 4th subpass)
+ // - rendering to a half sized render buffer (can't do 4th subpass)
+ // We'll need to restrict how far we're going with subpasses based on this.
Size2i screen_size;
- RID opaque_framebuffer;
- RID alpha_framebuffer;
+ RID framebuffer;
bool reverse_cull = false;
+ bool using_subpass_transparent = true;
+ bool using_subpass_post_process = true;
+
+ bool using_ssr = false; // I don't think we support this in our mobile renderer so probably should phase it out
+ bool using_sss = false; // I don't think we support this in our mobile renderer so probably should phase it out
+
+ // fill our render lists early so we can find out if we use various features
+ _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR);
+ render_list[RENDER_LIST_OPAQUE].sort_by_key();
+ render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
+ _fill_element_info(RENDER_LIST_OPAQUE);
+ _fill_element_info(RENDER_LIST_ALPHA);
- // I don't think we support either of these in our mobile renderer so probably should phase them out
- bool using_ssr = false;
- bool using_sss = false;
+ if (p_render_data->render_info) {
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_render_data->instances->size();
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = p_render_data->instances->size();
+ }
if (render_buffer) {
// setup rendering to render buffer
screen_size.x = render_buffer->width;
screen_size.y = render_buffer->height;
- opaque_framebuffer = render_buffer->color_fb;
- alpha_framebuffer = opaque_framebuffer;
+ if (render_buffer->color_fbs[FB_CONFIG_FOUR_SUBPASSES].is_null()) {
+ // can't do blit subpass
+ using_subpass_post_process = false;
+ } else if (env && (env->glow_enabled || env->auto_exposure || camera_effects_uses_dof(p_render_data->camera_effects))) {
+ // can't do blit subpass
+ using_subpass_post_process = false;
+ }
+
+ if (using_ssr || using_sss || scene_state.used_screen_texture || scene_state.used_depth_texture) {
+ // can't use our last two subpasses
+ using_subpass_transparent = false;
+ using_subpass_post_process = false;
+ }
+
+ if (using_subpass_post_process) {
+ // all as subpasses
+ framebuffer = render_buffer->color_fbs[FB_CONFIG_FOUR_SUBPASSES];
+ } else if (using_subpass_transparent) {
+ // our tonemap pass is separate
+ framebuffer = render_buffer->color_fbs[FB_CONFIG_THREE_SUBPASSES];
+ } else {
+ // only opaque and sky as subpasses
+ framebuffer = render_buffer->color_fbs[FB_CONFIG_TWO_SUBPASSES];
+ }
} else if (p_render_data->reflection_probe.is_valid()) {
uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
screen_size.x = resolution;
screen_size.y = resolution;
- opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
- alpha_framebuffer = opaque_framebuffer;
+ framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
p_render_data->environment = RID(); //no environment on interiors
@@ -350,6 +555,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
reverse_cull = true;
+ using_subpass_transparent = true; // we ignore our screen/depth texture here
+ using_subpass_post_process = false; // not applicable at all for reflection probes.
} else {
ERR_FAIL(); //bug?
}
@@ -361,17 +568,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
_update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
- _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR);
- render_list[RENDER_LIST_OPAQUE].sort_by_key();
- render_list[RENDER_LIST_ALPHA].sort_by_depth();
-
- // we no longer use this...
- _fill_instance_data(RENDER_LIST_OPAQUE);
- _fill_instance_data(RENDER_LIST_ALPHA);
-
- RD::get_singleton()->draw_command_end_label();
-
- // note, no depth prepass here!
+ RD::get_singleton()->draw_command_end_label(); // Render Setup
// setup environment
RID radiance_texture;
@@ -440,101 +637,234 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RID sky_rid = env->sky;
if (sky_rid.is_valid()) {
- sky.update(env, projection, p_render_data->cam_transform, time);
+ sky.update(env, projection, p_render_data->cam_transform, time, _render_buffers_get_luminance_multiplier());
radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
} else {
// do not try to draw sky if invalid
draw_sky = false;
}
- RD::get_singleton()->draw_command_end_label();
+ RD::get_singleton()->draw_command_end_label(); // Setup Sky
}
} else {
clear_color = p_default_bg_color;
}
- // opaque pass
+ // update sky buffers (if required)
+ if (draw_sky || draw_sky_fog_only) {
+ // !BAS! @TODO See if we can limit doing some things double and maybe even move this into _pre_opaque_render
+ // and change Forward Clustered in the same way as we have here (but without using subpasses)
+ RENDER_TIMESTAMP("Setup Sky resolution buffers");
- // !BAS! Look into this, seems most of the code in here related to clustered only, may want to move this code into ForwardClustered/RenderForwardMobile before calling it from here
- // does trigger shadow map rendering so kinda important
- _pre_opaque_render(p_render_data, false, false, RID(), RID());
+ RD::get_singleton()->draw_command_begin_label("Setup Sky resolution buffers");
- RD::get_singleton()->draw_command_begin_label("Render Opaque Pass");
+ if (p_render_data->reflection_probe.is_valid()) {
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ CameraMatrix projection = correction * p_render_data->cam_projection;
+ sky.update_res_buffers(env, 1, &projection, p_render_data->cam_transform, time);
+ } else {
+ sky.update_res_buffers(env, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time);
+ }
- scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
+ RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers
+ }
- _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid());
+ _pre_opaque_render(p_render_data, false, false, RID(), RID());
- RENDER_TIMESTAMP("Render Opaque Pass");
+ uint32_t spec_constant_base_flags = 0;
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true);
+ {
+ //figure out spec constants
- bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss;
- bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss;
+ if (p_render_data->directional_light_count > 0) {
+ if (p_render_data->directional_light_soft_shadows) {
+ spec_constant_base_flags |= 1 << SPEC_CONSTANT_USING_DIRECTIONAL_SOFT_SHADOWS;
+ }
+ } else {
+ spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS;
+ }
+ if (!is_environment(p_render_data->environment) || environment_is_fog_enabled(p_render_data->environment)) {
+ spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_FOG;
+ }
+ }
{
- bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
- bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
+ if (render_buffer) {
+ RD::get_singleton()->draw_command_begin_label("Render 3D Pass");
+ } else {
+ RD::get_singleton()->draw_command_begin_label("Render Reflection Probe Pass");
+ }
- // regular forward for now
- Vector<Color> c;
- c.push_back(clear_color.to_linear());
+ // opaque pass
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
- _render_list_with_threads(&render_list_params, opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
- }
+ RD::get_singleton()->draw_command_begin_label("Render Opaque Subpass");
- RD::get_singleton()->draw_command_end_label();
+ scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
- if (draw_sky || draw_sky_fog_only) {
- RENDER_TIMESTAMP("Render Sky");
+ _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid());
- CameraMatrix projection = p_render_data->cam_projection;
- if (p_render_data->reflection_probe.is_valid()) {
- CameraMatrix correction;
- correction.set_depth_correction(true);
- projection = correction * p_render_data->cam_projection;
+ if (using_subpass_transparent && using_subpass_post_process) {
+ RENDER_TIMESTAMP("Render Opaque + Transparent + Tonemap");
+ } else if (using_subpass_transparent) {
+ RENDER_TIMESTAMP("Render Opaque + Transparent");
+ } else {
+ RENDER_TIMESTAMP("Render Opaque");
}
- RD::get_singleton()->draw_command_begin_label("Draw Sky");
- sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, projection, p_render_data->cam_transform, time);
- RD::get_singleton()->draw_command_end_label();
- }
- 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);
- /*
- if (using_separate_specular) {
- RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular);
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true);
+
+ bool can_continue_color = !using_subpass_transparent && !scene_state.used_screen_texture && !using_ssr && !using_sss;
+ bool can_continue_depth = !using_subpass_transparent && !scene_state.used_depth_texture && !using_ssr && !using_sss;
+
+ {
+ // regular forward for now
+ Vector<Color> c;
+ c.push_back(clear_color.to_linear()); // our render buffer
+ if (render_buffer) {
+ if (render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ c.push_back(clear_color.to_linear()); // our resolve buffer
+ }
+ if (using_subpass_post_process) {
+ c.push_back(Color()); // our 2D buffer we're copying into
+ }
+ }
+
+ RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
+ render_list_params.framebuffer_format = fb_format;
+ if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
+ // secondary command buffers need more testing at this time
+ //multi threaded
+ thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
+ RD::get_singleton()->draw_list_begin_split(framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
+ RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, &render_list_params);
+ } else {
+ //single threaded
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
+ _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
+ }
}
- */
- }
- 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);
- }
+ RD::get_singleton()->draw_command_end_label(); //Render Opaque Subpass
- // transparent pass
- RENDER_TIMESTAMP("Render Transparent Pass");
+ if (draw_sky || draw_sky_fog_only) {
+ RD::get_singleton()->draw_command_begin_label("Draw Sky Subpass");
- RD::get_singleton()->draw_command_begin_label("Render Transparent Pass");
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
- rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true);
+ if (p_render_data->reflection_probe.is_valid()) {
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ CameraMatrix projection = correction * p_render_data->cam_projection;
+ sky.draw(draw_list, env, framebuffer, 1, &projection, p_render_data->cam_transform, time, _render_buffers_get_luminance_multiplier());
+ } else {
+ sky.draw(draw_list, env, framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time, _render_buffers_get_luminance_multiplier());
+ }
- _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
+ RD::get_singleton()->draw_command_end_label(); // Draw Sky Subpass
- {
- RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
- _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
+ // note, if MSAA is used in 2-subpass approach we should get an automatic resolve here
+ } else {
+ // switch to subpass but we do nothing here so basically we skip (though this should trigger resolve with 2-subpass MSAA).
+ RD::get_singleton()->draw_list_switch_to_next_pass();
+ }
+
+ if (!using_subpass_transparent) {
+ // We're done with our subpasses so end our container pass
+ RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL);
+
+ RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass
+ }
+
+ if (scene_state.used_screen_texture) {
+ // Copy screen texture to backbuffer so we can read from it
+ _render_buffers_copy_screen_texture(p_render_data);
+ }
+
+ if (scene_state.used_depth_texture) {
+ // Copy depth texture to backbuffer so we can read from it
+ _render_buffers_copy_depth_texture(p_render_data);
+ }
+
+ // transparent pass
+
+ RD::get_singleton()->draw_command_begin_label("Render Transparent Subpass");
+
+ rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true);
+
+ if (using_subpass_transparent) {
+ RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR_TRANSPARENT, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
+ render_list_params.framebuffer_format = fb_format;
+ if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
+ // secondary command buffers need more testing at this time
+ //multi threaded
+ thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
+ RD::get_singleton()->draw_list_switch_to_next_pass_split(thread_draw_lists.size(), thread_draw_lists.ptr());
+ render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass();
+ RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, &render_list_params);
+ } else {
+ //single threaded
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
+ render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass();
+ _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
+ }
+
+ RD::get_singleton()->draw_command_end_label(); // Render Transparent Subpass
+
+ // note if we are using MSAA we should get an automatic resolve through our subpass configuration.
+
+ // blit to tonemap
+ if (render_buffer && using_subpass_post_process) {
+ _post_process_subpass(render_buffer->color, framebuffer, p_render_data);
+ }
+
+ RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass
+
+ RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL);
+ } else {
+ RENDER_TIMESTAMP("Render Transparent");
+
+ framebuffer = render_buffer->color_fbs[FB_CONFIG_ONE_PASS];
+
+ // this may be needed if we re-introduced steps that change info, not sure which do so in the previous implementation
+ // _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
+
+ RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
+ render_list_params.framebuffer_format = fb_format;
+ if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
+ // secondary command buffers need more testing at this time
+ //multi threaded
+ thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
+ RD::get_singleton()->draw_list_begin_split(framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
+ RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, &render_list_params);
+ RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL);
+ } else {
+ //single threaded
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
+ _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
+ RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL);
+ }
+
+ RD::get_singleton()->draw_command_end_label(); // Render Transparent Subpass
+ }
}
- RD::get_singleton()->draw_command_end_label();
+ if (render_buffer && !using_subpass_post_process) {
+ RD::get_singleton()->draw_command_begin_label("Post process pass");
+
+ // If we need extra effects we do this in its own pass
+ RENDER_TIMESTAMP("Tonemap");
- RD::get_singleton()->draw_command_begin_label("Resolve");
+ _render_buffers_post_process_and_tonemap(p_render_data);
- if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
- RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color);
+ RD::get_singleton()->draw_command_end_label(); // Post process pass
}
- RD::get_singleton()->draw_command_end_label();
+ if (render_buffer) {
+ _disable_clear_request(p_render_data);
+ }
}
/* these are being called from RendererSceneRenderRD::_pre_opaque_render */
@@ -547,21 +877,28 @@ void RenderForwardMobile::_render_shadow_begin() {
render_list[RENDER_LIST_SECONDARY].clear();
}
-void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, 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, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) {
+void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &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, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RendererScene::RenderInfo *p_render_info) {
uint32_t shadow_pass_index = scene_state.shadow_passes.size();
SceneState::ShadowPass shadow_pass;
+ if (p_render_info) {
+ p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_instances.size();
+ p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = p_instances.size();
+ }
RenderDataRD render_data;
render_data.cam_projection = p_projection;
render_data.cam_transform = p_transform;
+ render_data.view_projection[0] = p_projection;
render_data.z_near = 0.0;
render_data.z_far = p_zfar;
render_data.instances = &p_instances;
+ render_data.render_info = p_render_info;
render_data.lod_camera_plane = p_camera_plane;
render_data.lod_distance_multiplier = p_lod_distance_multiplier;
scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
+ scene_state.ubo.opaque_prepass_threshold = 0.1;
_setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index);
@@ -577,7 +914,7 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, true);
uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from;
render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size);
- _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size, false);
+ _fill_element_info(RENDER_LIST_SECONDARY, render_list_from, render_list_size);
{
//regular forward for now
@@ -622,7 +959,7 @@ void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) {
for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i];
- RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
+ RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
_render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect);
}
@@ -634,7 +971,7 @@ void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) {
/* */
-void RenderForwardMobile::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
RENDER_TIMESTAMP("Setup Rendering Material");
RD::get_singleton()->draw_command_begin_label("Render Material");
@@ -643,10 +980,12 @@ void RenderForwardMobile::_render_material(const Transform &p_cam_transform, con
scene_state.ubo.dual_paraboloid_side = 0;
scene_state.ubo.material_uv2_mode = false;
+ scene_state.ubo.opaque_prepass_threshold = 0.0f;
RenderDataRD render_data;
render_data.cam_projection = p_cam_projection;
render_data.cam_transform = p_cam_transform;
+ render_data.view_projection[0] = p_cam_projection;
render_data.instances = &p_instances;
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
@@ -654,14 +993,14 @@ void RenderForwardMobile::_render_material(const Transform &p_cam_transform, con
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
- _fill_instance_data(RENDER_LIST_SECONDARY);
+ _fill_element_info(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
RENDER_TIMESTAMP("Render Material");
{
- RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, 0);
//regular forward for now
Vector<Color> clear;
clear.push_back(Color(0, 0, 0, 0));
@@ -695,14 +1034,14 @@ void RenderForwardMobile::_render_uv2(const PagedArray<GeometryInstance *> &p_in
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
- _fill_instance_data(RENDER_LIST_SECONDARY);
+ _fill_element_info(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
RENDER_TIMESTAMP("Render Material");
{
- RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, true);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, true, 0);
//regular forward for now
Vector<Color> clear;
clear.push_back(Color(0, 0, 0, 0));
@@ -746,17 +1085,19 @@ void RenderForwardMobile::_render_sdfgi(RID p_render_buffers, const Vector3i &p_
// we don't do GI in low end..
}
-void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) {
+void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) {
RENDER_TIMESTAMP("Setup Render Collider Heightfield");
RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
_update_render_base_uniform_set();
scene_state.ubo.dual_paraboloid_side = 0;
+ scene_state.ubo.opaque_prepass_threshold = 0.0;
RenderDataRD render_data;
render_data.cam_projection = p_cam_projection;
render_data.cam_transform = p_cam_transform;
+ render_data.view_projection[0] = p_cam_projection;
render_data.z_near = 0.0;
render_data.z_far = p_cam_projection.get_z_far();
render_data.instances = &p_instances;
@@ -767,7 +1108,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
- _fill_instance_data(RENDER_LIST_SECONDARY);
+ _fill_element_info(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
@@ -775,7 +1116,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
{
//regular forward for now
- RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, rp_uniform_set);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, rp_uniform_set, 0);
_render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ);
}
RD::get_singleton()->draw_command_end_label();
@@ -832,13 +1173,67 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
{
RD::Uniform u;
u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ RID sampler;
+ switch (decals_get_filter()) {
+ case RS::DECAL_FILTER_NEAREST: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ }
+
+ u.ids.push_back(sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ RID sampler;
+ switch (light_projectors_get_filter()) {
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ }
+
+ u.ids.push_back(sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_omni_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 4;
+ u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_spot_light_buffer());
uniforms.push_back(u);
@@ -846,35 +1241,35 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
{
RD::Uniform u;
- u.binding = 5;
+ u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_reflection_probe_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 6;
+ u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.ids.push_back(get_directional_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 7;
+ u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(scene_state.lightmap_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 8;
+ u.binding = 10;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(scene_state.lightmap_capture_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 9;
+ u.binding = 11;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID decal_atlas = storage->decal_atlas_get_texture();
u.ids.push_back(decal_atlas);
@@ -882,7 +1277,7 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
}
{
RD::Uniform u;
- u.binding = 10;
+ u.binding = 12;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID decal_atlas = storage->decal_atlas_get_texture_srgb();
u.ids.push_back(decal_atlas);
@@ -890,7 +1285,7 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
}
{
RD::Uniform u;
- u.binding = 11;
+ u.binding = 13;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_decal_buffer());
uniforms.push_back(u);
@@ -899,7 +1294,7 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 12;
+ u.binding = 14;
u.ids.push_back(storage->global_variables_get_storage_buffer());
uniforms.push_back(u);
}
@@ -916,6 +1311,12 @@ RID RenderForwardMobile::_render_buffers_get_normal_texture(RID p_render_buffers
return RID();
}
+_FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primitive, uint32_t p_indices) {
+ static const uint32_t divisor[RS::PRIMITIVE_MAX] = { 1, 2, 1, 3, 1 };
+ static const uint32_t subtractor[RS::PRIMITIVE_MAX] = { 0, 0, 1, 0, 1 };
+ return (p_indices - subtractor[p_primitive]) / divisor[p_primitive];
+}
+
void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append) {
if (p_render_list == RENDER_LIST_OPAQUE) {
scene_state.used_sss = false;
@@ -925,7 +1326,7 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
}
uint32_t lightmap_captures_used = 0;
- Plane near_plane(p_render_data->cam_transform.origin, -p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z));
+ Plane near_plane(-p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z), p_render_data->cam_transform.origin);
near_plane.d += p_render_data->cam_projection.get_z_near();
float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near();
@@ -952,6 +1353,10 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
uint32_t flags = inst->base_flags; //fill flags if appropriate
+ if (inst->non_uniform_scale) {
+ flags |= INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE;
+ }
+
bool uses_lightmap = false;
// bool uses_gi = false;
@@ -1021,21 +1426,42 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
distance = -distance_max;
}
- surf->lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
+ uint32_t indices;
+ surf->lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, &indices);
+ if (p_render_data->render_info) {
+ indices = _indices_to_primitives(surf->primitive, indices);
+ if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices;
+ } else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices;
+ }
+ }
} else {
surf->lod_index = 0;
+ if (p_render_data->render_info) {
+ uint32_t to_draw = storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ to_draw = _indices_to_primitives(surf->primitive, to_draw);
+ to_draw *= inst->instance_count;
+ if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ } else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ }
+ }
}
// ADD Element
- if (p_pass_mode == PASS_MODE_COLOR) {
- if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) {
+ if (p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
+#ifdef DEBUG_ENABLED
+ bool force_alpha = unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW);
+#else
+ bool force_alpha = false;
+#endif
+ if (!force_alpha && (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) {
rl->add_element(surf);
}
- if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA) {
+ if (force_alpha || (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA)) {
render_list[RENDER_LIST_ALPHA].add_element(surf);
- // if (uses_gi) {
- // surf->sort.uses_forward_gi = 1;
- // }
}
if (uses_lightmap) {
@@ -1089,6 +1515,12 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
RendererStorageRD::store_transform(p_render_data->cam_transform, scene_state.ubo.camera_matrix);
RendererStorageRD::store_transform(p_render_data->cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix);
+ for (uint32_t v = 0; v < p_render_data->view_count; v++) {
+ projection = correction * p_render_data->view_projection[v];
+ RendererStorageRD::store_camera(projection, scene_state.ubo.projection_matrix_view[v]);
+ RendererStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix_view[v]);
+ }
+
scene_state.ubo.z_far = p_render_data->z_far;
scene_state.ubo.z_near = p_render_data->z_near;
@@ -1099,11 +1531,6 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
RendererStorageRD::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel);
RendererStorageRD::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();
-
Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
@@ -1210,19 +1637,10 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_render_data->environment);
scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_render_data->environment);
- Color ao_color = environment_get_ao_color(p_render_data->environment).to_linear();
- scene_state.ubo.ao_color[0] = ao_color.r;
- scene_state.ubo.ao_color[1] = ao_color.g;
- scene_state.ubo.ao_color[2] = ao_color.b;
- scene_state.ubo.ao_color[3] = ao_color.a;
-
scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_render_data->environment);
scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment);
scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment);
scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment);
- if (scene_state.ubo.fog_height_density >= 0.0001) {
- scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density;
- }
scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment);
Color fog_color = environment_get_fog_light_color(p_render_data->environment).to_linear();
@@ -1267,9 +1685,7 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER);
}
-void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
- // !BAS! Rename this to make clear this is not the same as with the forward renderer and remove p_update_buffer?
-
+void RenderForwardMobile::_fill_element_info(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements) {
RenderList *rl = &render_list[p_render_list];
uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size();
@@ -1334,6 +1750,57 @@ void RenderForwardMobile::_render_list_with_threads(RenderListParameters *p_para
}
}
+void RenderForwardMobile::_fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance) {
+ // first zero out our indices
+
+ p_push_constant->omni_lights[0] = 0xFFFF;
+ p_push_constant->omni_lights[1] = 0xFFFF;
+
+ p_push_constant->spot_lights[0] = 0xFFFF;
+ p_push_constant->spot_lights[1] = 0xFFFF;
+
+ p_push_constant->decals[0] = 0xFFFF;
+ p_push_constant->decals[1] = 0xFFFF;
+
+ p_push_constant->reflection_probes[0] = 0xFFFF;
+ p_push_constant->reflection_probes[1] = 0xFFFF;
+
+ if (p_instance->omni_light_count == 0) {
+ spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS;
+ }
+ if (p_instance->spot_light_count == 0) {
+ spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS;
+ }
+ if (p_instance->reflection_probe_count == 0) {
+ spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES;
+ }
+ if (p_instance->decals_count == 0) {
+ spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS;
+ }
+
+ for (uint32_t i = 0; i < MAX_RDL_CULL; i++) {
+ uint32_t ofs = i < 4 ? 0 : 1;
+ uint32_t shift = (i & 0x3) << 3;
+ uint32_t mask = ~(0xFF << shift);
+ if (i < p_instance->omni_light_count) {
+ p_push_constant->omni_lights[ofs] &= mask;
+ p_push_constant->omni_lights[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift;
+ }
+ if (i < p_instance->spot_light_count) {
+ p_push_constant->spot_lights[ofs] &= mask;
+ p_push_constant->spot_lights[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift;
+ }
+ if (i < p_instance->decals_count) {
+ p_push_constant->decals[ofs] &= mask;
+ p_push_constant->decals[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift;
+ }
+ if (i < p_instance->reflection_probe_count) {
+ p_push_constant->reflection_probes[ofs] &= mask;
+ p_push_constant->reflection_probes[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift;
+ }
+ }
+}
+
template <RenderForwardMobile::PassMode p_pass_mode>
void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
RD::DrawListID draw_list = p_draw_list;
@@ -1358,13 +1825,19 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
const RenderElementInfo &element_info = p_params->element_info[i];
const GeometryInstanceForwardMobile *inst = surf->owner;
+ if (inst->instance_count == 0) {
+ continue;
+ }
+
+ uint32_t base_spec_constants = p_params->spec_constant_base_flags;
+
// GeometryInstanceForwardMobile::PushConstant push_constant = inst->push_constant;
GeometryInstanceForwardMobile::PushConstant push_constant;
if (inst->store_transform_cache) {
RendererStorageRD::store_transform(inst->transform, push_constant.transform);
} else {
- RendererStorageRD::store_transform(Transform(), push_constant.transform);
+ RendererStorageRD::store_transform(Transform3D(), push_constant.transform);
}
push_constant.flags = inst->flags_cache;
@@ -1383,8 +1856,6 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
push_constant.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y;
};
- _fill_instance_indices(inst->omni_lights, inst->omni_light_count, push_constant.omni_lights, inst->spot_lights, inst->spot_light_count, push_constant.spot_lights, inst->reflection_probes, inst->reflection_probe_count, push_constant.reflection_probes, inst->decals, inst->decals_count, push_constant.decals, push_constant.layer_mask);
-
RID material_uniform_set;
SceneShaderForwardMobile::ShaderData *shader;
void *mesh_surface;
@@ -1395,8 +1866,28 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
mesh_surface = surf->surface_shadow;
} else {
- material_uniform_set = surf->material_uniform_set;
- shader = surf->shader;
+ if (inst->use_projector) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_USING_PROJECTOR;
+ }
+ if (inst->use_soft_shadow) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_USING_SOFT_SHADOWS;
+ }
+ _fill_push_constant_instance_indices(&push_constant, base_spec_constants, inst);
+
+#ifdef DEBUG_ENABLED
+ if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) {
+ material_uniform_set = scene_shader.default_material_uniform_set;
+ shader = scene_shader.default_material_shader_ptr;
+ } else if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW)) {
+ material_uniform_set = scene_shader.overdraw_material_uniform_set;
+ shader = scene_shader.overdraw_material_shader_ptr;
+ } else {
+#endif
+ material_uniform_set = surf->material_uniform_set;
+ shader = surf->shader;
+#ifdef DEBUG_ENABLED
+ }
+#endif
mesh_surface = surf->surface;
}
@@ -1426,18 +1917,20 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
case PASS_MODE_COLOR:
case PASS_MODE_COLOR_TRANSPARENT: {
if (element_info.uses_lightmap) {
- shader_version = SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS;
+ shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS;
} else {
- shader_version = SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS;
+ shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS;
}
} break;
case PASS_MODE_SHADOW: {
- shader_version = SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS;
+ shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS;
} break;
case PASS_MODE_SHADOW_DP: {
- shader_version = SceneShaderForwardMobile::SHADER_VERSION_DEPTH_PASS_DP;
+ ERR_FAIL_COND_MSG(p_params->view_count > 1, "Multiview not supported for shadow DP pass");
+ shader_version = SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS_DP;
} break;
case PASS_MODE_DEPTH_MATERIAL: {
+ ERR_FAIL_COND_MSG(p_params->view_count > 1, "Multiview not supported for material pass");
shader_version = SceneShaderForwardMobile::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
} break;
}
@@ -1471,7 +1964,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
prev_index_array_rd = index_array_rd;
}
- RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe);
+ RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe, p_params->subpass, base_spec_constants);
if (pipeline_rd != prev_pipeline_rd) {
// checking with prev shader does not make so much sense, as
@@ -1486,8 +1979,8 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
}
if (material_uniform_set != prev_material_uniform_set) {
- //update uniform set
- if (material_uniform_set.is_valid()) {
+ // Update uniform set.
+ if (material_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material_uniform_set)) { // Material may not have a uniform set.
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET);
}
@@ -1557,7 +2050,7 @@ void RenderForwardMobile::geometry_instance_set_mesh_instance(GeometryInstance *
_geometry_instance_mark_dirty(ginstance);
}
-void RenderForwardMobile::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
+void RenderForwardMobile::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->transform = p_transform;
@@ -1587,6 +2080,15 @@ void RenderForwardMobile::geometry_instance_set_lod_bias(GeometryInstance *p_geo
ginstance->lod_bias = p_lod_bias;
}
+void RenderForwardMobile::geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) {
+}
+
+void RenderForwardMobile::geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) {
+}
+
+void RenderForwardMobile::geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) {
+}
+
void RenderForwardMobile::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) {
GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
@@ -1645,9 +2147,9 @@ void RenderForwardMobile::geometry_instance_set_cast_double_sided_shadows(Geomet
_geometry_instance_mark_dirty(ginstance);
}
-Transform RenderForwardMobile::geometry_instance_get_transform(GeometryInstance *p_instance) {
+Transform3D RenderForwardMobile::geometry_instance_get_transform(GeometryInstance *p_instance) {
GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_instance);
- ERR_FAIL_COND_V(!ginstance, Transform());
+ ERR_FAIL_COND_V(!ginstance, Transform3D());
return ginstance->transform;
}
@@ -1689,13 +2191,13 @@ void RenderForwardMobile::geometry_instance_pair_light_instances(GeometryInstanc
switch (type) {
case RS::LIGHT_OMNI: {
if (ginstance->omni_light_count < (uint32_t)MAX_RDL_CULL) {
- ginstance->omni_lights[ginstance->omni_light_count] = p_light_instances[i];
+ ginstance->omni_lights[ginstance->omni_light_count] = light_instance_get_forward_id(p_light_instances[i]);
ginstance->omni_light_count++;
}
} break;
case RS::LIGHT_SPOT: {
if (ginstance->spot_light_count < (uint32_t)MAX_RDL_CULL) {
- ginstance->spot_lights[ginstance->spot_light_count] = p_light_instances[i];
+ ginstance->spot_lights[ginstance->spot_light_count] = light_instance_get_forward_id(p_light_instances[i]);
ginstance->spot_light_count++;
}
} break;
@@ -1711,7 +2213,7 @@ void RenderForwardMobile::geometry_instance_pair_reflection_probe_instances(Geom
ginstance->reflection_probe_count = p_reflection_probe_instance_count < (uint32_t)MAX_RDL_CULL ? p_reflection_probe_instance_count : (uint32_t)MAX_RDL_CULL;
for (uint32_t i = 0; i < ginstance->reflection_probe_count; i++) {
- ginstance->reflection_probes[i] = p_reflection_probe_instances[i];
+ ginstance->reflection_probes[i] = reflection_probe_instance_get_forward_id(p_reflection_probe_instances[i]);
}
}
@@ -1721,14 +2223,22 @@ void RenderForwardMobile::geometry_instance_pair_decal_instances(GeometryInstanc
ginstance->decals_count = p_decal_instance_count < (uint32_t)MAX_RDL_CULL ? p_decal_instance_count : (uint32_t)MAX_RDL_CULL;
for (uint32_t i = 0; i < ginstance->decals_count; i++) {
- ginstance->decals[i] = p_decal_instances[i];
+ ginstance->decals[i] = decal_instance_get_forward_id(p_decal_instances[i]);
}
}
-void RenderForwardMobile::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) {
+void RenderForwardMobile::geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) {
// We do not have this here!
}
+void RenderForwardMobile::geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+
+ ginstance->use_projector = p_projector;
+ ginstance->use_soft_shadow = p_softshadow;
+}
+
void RenderForwardMobile::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) {
GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
if (ginstance->dirty_list_element.in_list()) {
@@ -1938,7 +2448,7 @@ void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry
} break;
#if 0
case RS::INSTANCE_IMMEDIATE: {
- RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base);
+ RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.get_or_null(inst->base);
ERR_CONTINUE(!immediate);
_add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass);
@@ -1976,6 +2486,7 @@ void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry
//Fill push constant
bool store_transform = true;
+ ginstance->base_flags = 0;
if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
@@ -2077,10 +2588,54 @@ uint32_t RenderForwardMobile::get_max_elements() const {
RenderForwardMobile *RenderForwardMobile::singleton = nullptr;
+void RenderForwardMobile::_update_shader_quality_settings() {
+ Vector<RD::PipelineSpecializationConstant> spec_constants;
+
+ RD::PipelineSpecializationConstant sc;
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
+
+ sc.constant_id = SPEC_CONSTANT_SOFT_SHADOW_SAMPLES;
+ sc.int_value = soft_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES;
+ sc.int_value = penumbra_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES;
+ sc.int_value = directional_soft_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES;
+ sc.int_value = directional_penumbra_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
+ sc.constant_id = SPEC_CONSTANT_DECAL_USE_MIPMAPS;
+ sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_PROJECTOR_USE_MIPMAPS;
+ sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+
+ spec_constants.push_back(sc);
+
+ scene_shader.set_default_specialization_constants(spec_constants);
+
+ _base_uniforms_changed(); //also need this
+}
+
RenderForwardMobile::RenderForwardMobile(RendererStorageRD *p_storage) :
RendererSceneRenderRD(p_storage) {
singleton = this;
+ sky.set_texture_format(_render_buffers_get_color_format());
+
String defines;
defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n";
@@ -2088,7 +2643,7 @@ RenderForwardMobile::RenderForwardMobile(RendererStorageRD *p_storage) :
defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";
}
// defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n";
- defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(get_max_directional_lights()) + "\n";
+ defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n";
{
//lightmaps
@@ -2112,6 +2667,8 @@ RenderForwardMobile::RenderForwardMobile(RendererStorageRD *p_storage) :
// !BAS! maybe we need a mobile version of this setting?
render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
+
+ _update_shader_quality_settings();
}
RenderForwardMobile::~RenderForwardMobile() {
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index bf911319f2..485d08b589 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -42,6 +42,18 @@ namespace RendererSceneRenderImplementation {
class RenderForwardMobile : public RendererSceneRenderRD {
friend SceneShaderForwardMobile;
+ struct ForwardIDAllocator {
+ LocalVector<bool> allocations;
+ LocalVector<uint8_t> map;
+ };
+
+ ForwardIDAllocator forward_id_allocators[FORWARD_ID_MAX];
+
+ virtual ForwardID _allocate_forward_id(ForwardIDType p_type) override;
+ virtual void _free_forward_id(ForwardIDType p_type, ForwardID p_id) override;
+ virtual void _map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) override;
+ virtual bool _uses_forward_ids() const override { return true; }
+
protected:
/* Scene Shader */
@@ -53,6 +65,30 @@ protected:
};
enum {
+
+ SPEC_CONSTANT_USING_PROJECTOR = 0,
+ SPEC_CONSTANT_USING_SOFT_SHADOWS = 1,
+ SPEC_CONSTANT_USING_DIRECTIONAL_SOFT_SHADOWS = 2,
+
+ SPEC_CONSTANT_SOFT_SHADOW_SAMPLES = 3,
+ SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES = 4,
+ SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES = 5,
+ SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES = 6,
+
+ SPEC_CONSTANT_DECAL_USE_MIPMAPS = 7,
+ SPEC_CONSTANT_PROJECTOR_USE_MIPMAPS = 8,
+
+ SPEC_CONSTANT_DISABLE_OMNI_LIGHTS = 9,
+ SPEC_CONSTANT_DISABLE_SPOT_LIGHTS = 10,
+ SPEC_CONSTANT_DISABLE_REFLECTION_PROBES = 11,
+ SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS = 12,
+
+ SPEC_CONSTANT_DISABLE_DECALS = 13,
+ SPEC_CONSTANT_DISABLE_FOG = 14,
+
+ };
+
+ enum {
MAX_LIGHTMAPS = 8,
MAX_RDL_CULL = 8, // maximum number of reflection probes, decals or lights we can cull per geometry instance
INSTANCE_DATA_BUFFER_MIN_SIZE = 4096
@@ -71,6 +107,18 @@ protected:
/* Render Buffer */
+ // We can have:
+ // - 4 subpasses combining the full render cycle
+ // - 3 subpasses + 1 normal pass for tonemapping/glow/dof/etc (using fb for 2D buffer)
+ // - 2 subpasses + 1 normal pass for transparent + 1 normal pass for tonemapping/glow/dof/etc (using fb for 2D buffer)
+ enum RenderBufferMobileFramebufferConfigType {
+ FB_CONFIG_ONE_PASS, // Single pass frame buffer for alpha pass
+ FB_CONFIG_TWO_SUBPASSES, // Opaque + Sky sub pass
+ FB_CONFIG_THREE_SUBPASSES, // Opaque + Sky + Alpha sub pass
+ FB_CONFIG_FOUR_SUBPASSES, // Opaque + Sky + Alpha sub pass + Tonemap pass
+ FB_CONFIG_MAX
+ };
+
struct RenderBufferDataForwardMobile : public RenderBufferData {
RID color;
RID depth;
@@ -83,16 +131,17 @@ protected:
RID depth_msaa;
// RID normal_roughness_buffer_msaa;
- RID color_fb;
+ RID color_fbs[FB_CONFIG_MAX];
int width, height;
+ uint32_t view_count;
void clear();
- virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa);
+ virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count);
~RenderBufferDataForwardMobile();
};
- virtual RenderBufferData *_create_render_buffer_data();
+ virtual RenderBufferData *_create_render_buffer_data() override;
/* Rendering */
@@ -104,7 +153,7 @@ protected:
PASS_MODE_SHADOW_DP,
// PASS_MODE_DEPTH,
// PASS_MODE_DEPTH_NORMAL_ROUGHNESS,
- // PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE,
+ // PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI,
PASS_MODE_DEPTH_MATERIAL,
// PASS_MODE_SDF,
};
@@ -120,23 +169,27 @@ protected:
bool reverse_cull = false;
PassMode pass_mode = PASS_MODE_COLOR;
// bool no_gi = false;
+ uint32_t view_count = 1;
RID render_pass_uniform_set;
bool force_wireframe = false;
Vector2 uv_offset;
Plane lod_plane;
+ uint32_t spec_constant_base_flags = 0;
float lod_distance_multiplier = 0.0;
float screen_lod_threshold = 0.0;
RD::FramebufferFormatID framebuffer_format = 0;
uint32_t element_offset = 0;
uint32_t barrier = RD::BARRIER_MASK_ALL;
+ uint32_t subpass = 0;
- RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
+ RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, uint32_t p_spec_constant_base_flags = 0, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
elements = p_elements;
element_info = p_element_info;
element_count = p_element_count;
reverse_cull = p_reverse_cull;
pass_mode = p_pass_mode;
// no_gi = p_no_gi;
+ view_count = p_view_count;
render_pass_uniform_set = p_render_pass_uniform_set;
force_wireframe = p_force_wireframe;
uv_offset = p_uv_offset;
@@ -145,36 +198,41 @@ protected:
screen_lod_threshold = p_screen_lod_threshold;
element_offset = p_element_offset;
barrier = p_barrier;
+ spec_constant_base_flags = p_spec_constant_base_flags;
}
};
+ virtual float _render_buffers_get_luminance_multiplier() override;
+ virtual RD::DataFormat _render_buffers_get_color_format() override;
+ virtual bool _render_buffers_can_be_storage() override;
+
RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0);
- virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color);
+ virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
- virtual void _render_shadow_begin();
- virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, 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, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true);
- virtual void _render_shadow_process();
- virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL);
+ virtual void _render_shadow_begin() override;
+ virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &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, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RendererScene::RenderInfo *p_render_info = nullptr) override;
+ virtual void _render_shadow_process() override;
+ virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override;
- virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
- virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
- virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture);
- virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances);
+ virtual void _render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
+ virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
+ virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) override;
+ virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) override;
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
- virtual void _base_uniforms_changed();
+ virtual void _base_uniforms_changed() override;
void _update_render_base_uniform_set();
- virtual RID _render_buffers_get_normal_texture(RID p_render_buffers);
+ virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) override;
void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false);
- void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
+ void _fill_element_info(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1);
// void _update_instance_data_buffer(RenderListType p_render_list);
static RenderForwardMobile *singleton;
void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
- void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform);
+ void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
RID render_base_uniform_set;
LocalVector<RID> render_pass_uniform_sets;
@@ -196,10 +254,12 @@ protected:
struct UBO {
float projection_matrix[16];
float inv_projection_matrix[16];
-
float camera_matrix[16];
float inv_camera_matrix[16];
+ float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
+ float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
+
float viewport_size[2];
float screen_pixel_size[2];
@@ -208,11 +268,6 @@ protected:
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];
float ambient_color_sky_mix;
@@ -237,9 +292,8 @@ protected:
float roughness_limiter_amount;
float roughness_limiter_limit;
- uint32_t roughness_limiter_pad[2];
-
- float ao_color[4];
+ float opaque_prepass_threshold;
+ uint32_t roughness_limiter_pad;
// Fog
uint32_t fog_enabled;
@@ -351,7 +405,7 @@ protected:
}
};
- void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha
+ void sort_by_reverse_depth_and_priority() { //used for alpha
SortArray<GeometryInstanceSurfaceDataCache *, SortByReverseDepthAndPriority> sorter;
sorter.sort(elements.ptr(), elements.size());
@@ -385,19 +439,19 @@ protected:
// check which ones of these apply, probably all except GI and SDFGI
enum {
+ INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5,
INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6,
INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7,
INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8,
INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9,
INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10,
- INSTANCE_DATA_FLAG_USE_GIPROBE = 1 << 11,
+ INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11,
INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15,
INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT = 16,
INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_MASK = 0xFF,
- INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 24,
};
struct GeometryInstanceLightmapSH {
@@ -489,7 +543,9 @@ protected:
RID transforms_uniform_set;
float depth = 0;
bool mirror = false;
- Transform transform;
+ bool use_projector = false;
+ bool use_soft_shadow = false;
+ Transform3D transform;
bool store_transform_cache = true; // if true we copy our transform into our PushConstant, if false we use our transforms UBO and clear our PushConstants transform
bool non_uniform_scale = false;
AABB transformed_aabb; //needed for LOD
@@ -508,14 +564,14 @@ protected:
GeometryInstanceLightmapSH *lightmap_sh = nullptr;
// culled light info
- uint32_t reflection_probe_count;
- RID reflection_probes[MAX_RDL_CULL];
- uint32_t omni_light_count;
- RID omni_lights[MAX_RDL_CULL];
- uint32_t spot_light_count;
- RID spot_lights[MAX_RDL_CULL];
- uint32_t decals_count;
- RID decals[MAX_RDL_CULL];
+ uint32_t reflection_probe_count = 0;
+ ForwardID reflection_probes[MAX_RDL_CULL];
+ uint32_t omni_light_count = 0;
+ ForwardID omni_lights[MAX_RDL_CULL];
+ uint32_t spot_light_count = 0;
+ ForwardID spot_lights[MAX_RDL_CULL];
+ uint32_t decals_count = 0;
+ ForwardID decals[MAX_RDL_CULL];
GeometryInstanceSurfaceDataCache *surface_caches = nullptr;
@@ -547,7 +603,13 @@ protected:
dirty_list_element(this) {}
};
+ _FORCE_INLINE_ void _fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance);
+
+ void _update_shader_quality_settings() override;
+
public:
+ virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth) override;
+
static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker);
static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker);
@@ -563,38 +625,43 @@ public:
void _geometry_instance_update(GeometryInstance *p_geometry_instance);
void _update_dirty_geometry_instances();
- virtual GeometryInstance *geometry_instance_create(RID p_base);
- virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton);
- virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override);
- virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials);
- virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance);
- virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb);
- virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask);
- virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias);
- virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable);
- virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable);
- virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index);
- virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9);
- virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset);
- virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable);
-
- virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance);
- virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance);
-
- virtual void geometry_instance_free(GeometryInstance *p_geometry_instance);
-
- virtual uint32_t geometry_instance_get_pair_mask();
- virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count);
- virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count);
- virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count);
- virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count);
-
- virtual bool free(RID p_rid);
-
- virtual bool is_dynamic_gi_supported() const;
- virtual bool is_clustered_enabled() const;
- virtual bool is_volumetric_supported() const;
- virtual uint32_t get_max_elements() const;
+ virtual GeometryInstance *geometry_instance_create(RID p_base) override;
+ virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override;
+ virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override;
+ virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) override;
+ virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override;
+ virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override;
+ virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) override;
+ virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) override;
+ virtual void geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) override;
+ virtual void geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) override;
+ virtual void geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) override;
+ virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) override;
+ virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) override;
+ virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override;
+ virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) override;
+ virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) override;
+ virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) override;
+
+ virtual Transform3D geometry_instance_get_transform(GeometryInstance *p_instance) override;
+ virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance) override;
+
+ virtual void geometry_instance_free(GeometryInstance *p_geometry_instance) override;
+
+ virtual uint32_t geometry_instance_get_pair_mask() override;
+ virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) override;
+ virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override;
+ virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) override;
+ virtual void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override;
+
+ virtual void geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) override;
+
+ virtual bool free(RID p_rid) override;
+
+ virtual bool is_dynamic_gi_supported() const override;
+ virtual bool is_clustered_enabled() const override;
+ virtual bool is_volumetric_supported() const override;
+ virtual uint32_t get_max_elements() const override;
RenderForwardMobile(RendererStorageRD *p_storage);
~RenderForwardMobile();
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index b9220cc514..e6d9a60f94 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -30,7 +30,9 @@
#include "scene_shader_forward_mobile.h"
#include "core/config/project_settings.h"
+#include "core/math/math_defs.h"
#include "render_forward_mobile.h"
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
using namespace RendererSceneRenderImplementation;
@@ -133,8 +135,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = shader_singleton->shader.version_create();
@@ -290,12 +291,12 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
multisample_state.enable_alpha_to_one = true;
}
- if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_MULTIVIEW || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW) {
blend_state = blend_state_blend;
if (depth_draw == DEPTH_DRAW_OPAQUE) {
depth_stencil.enable_depth_write = false; //alpha does not draw depth
}
- } else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
+ } else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_SHADOW_PASS_MULTIVIEW || k == SHADER_VERSION_SHADOW_PASS_DP) {
//none, blend state contains nothing
} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
@@ -303,61 +304,20 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
pipelines[i][j][k].clear();
continue; // do not use this version (will error if using it is attempted)
}
-
- /*
- if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
- blend_state = blend_state_blend;
- if (depth_draw == DEPTH_DRAW_OPAQUE) {
- depth_stencil.enable_depth_write = false; //alpha does not draw depth
- }
- } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) {
- if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
- //none, blend state contains nothing
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
- blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
- } else {
- blend_state = blend_state_opaque; //writes to normal and roughness in opaque way
- }
- } else {
- pipelines[i][j][k].clear();
- continue; // do not use this version (will error if using it is attempted)
- }
- */
} else {
- if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_MULTIVIEW || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW) {
blend_state = blend_state_opaque;
- } else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
+ } else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_SHADOW_PASS_MULTIVIEW || k == SHADER_VERSION_SHADOW_PASS_DP) {
//none, leave empty
} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
} else {
// ???
}
-
- /*
- if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
- blend_state = blend_state_opaque;
- } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
- //none, leave empty
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) {
- blend_state = blend_state_depth_normal_roughness;
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) {
- blend_state = blend_state_depth_normal_roughness_giprobe;
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
- blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) {
- blend_state = RD::PipelineColorBlendState(); //no color targets for SDF
- } else {
- //specular write
- blend_state = blend_state_opaque_specular;
- depth_stencil.enable_depth_test = false;
- depth_stencil.enable_depth_write = false;
- }
- */
}
RID shader_variant = shader_singleton->shader.version_get_shader(version, k);
- pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0);
+ pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0, singleton->default_specialization_constants);
}
}
}
@@ -365,47 +325,56 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
valid = true;
}
-void SceneShaderForwardMobile::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+void SceneShaderForwardMobile::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
- default_texture_params.erase(p_name);
+ if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
+ default_texture_params[p_name].erase(p_index);
+
+ if (default_texture_params[p_name].is_empty()) {
+ default_texture_params.erase(p_name);
+ }
+ }
} else {
- default_texture_params[p_name] = p_texture;
+ if (!default_texture_params.has(p_name)) {
+ default_texture_params[p_name] = Map<int, RID>();
+ }
+ default_texture_params[p_name][p_index] = p_texture;
}
}
void SceneShaderForwardMobile::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
Map<int, StringName> order;
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
continue;
}
- if (E->get().texture_order >= 0) {
- order[E->get().texture_order + 100000] = E->key();
+ if (E.value.texture_order >= 0) {
+ order[E.value.texture_order + 100000] = E.key;
} else {
- order[E->get().order] = E->key();
+ order[E.value.order] = E.key;
}
}
- for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
- pi.name = E->get();
+ for (const KeyValue<int, StringName> &E : order) {
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
+ pi.name = E.value;
p_param_list->push_back(pi);
}
}
void SceneShaderForwardMobile::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
RendererStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E->get());
- p.info.name = E->key(); //supply name
- p.index = E->get().instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+ p.info = ShaderLanguage::uniform_to_property_info(E.value);
+ p.info.name = E.key; //supply name
+ p.index = E.value.instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
p_param_list->push_back(p);
}
}
@@ -430,7 +399,7 @@ Variant SceneShaderForwardMobile::ShaderData::get_default_parameter(const String
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
return Variant();
}
@@ -441,7 +410,8 @@ RS::ShaderNativeSourceCode SceneShaderForwardMobile::ShaderData::get_native_sour
return shader_singleton->shader.version_get_native_source_code(version);
}
-SceneShaderForwardMobile::ShaderData::ShaderData() {
+SceneShaderForwardMobile::ShaderData::ShaderData() :
+ shader_list_element(this) {
valid = false;
uses_screen_texture = false;
}
@@ -457,6 +427,7 @@ SceneShaderForwardMobile::ShaderData::~ShaderData() {
RendererStorageRD::ShaderData *SceneShaderForwardMobile::_create_shader_func() {
ShaderData *shader_data = memnew(ShaderData);
+ singleton->shader_list.add(&shader_data->shader_list_element);
return shader_data;
}
@@ -468,94 +439,14 @@ void SceneShaderForwardMobile::MaterialData::set_next_pass(RID p_pass) {
next_pass = p_pass;
}
-void SceneShaderForwardMobile::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+bool SceneShaderForwardMobile::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
- if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
- p_uniform_dirty = true;
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- uniform_buffer = RID();
- }
-
- ubo_data.resize(shader_data->ubo_size);
- if (ubo_data.size()) {
- uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
- memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
- }
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
-
- //check whether buffer changed
- if (p_uniform_dirty && ubo_data.size()) {
- update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
- RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER);
- }
-
- uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
-
- if ((uint32_t)texture_cache.size() != tex_uniform_count) {
- texture_cache.resize(tex_uniform_count);
- p_textures_dirty = true;
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
-
- if (p_textures_dirty && tex_uniform_count) {
- update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true);
- }
-
- if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) {
- // This material does not require an uniform set, so don't create it.
- return;
- }
-
- if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- //no reason to update uniform set, only UBO (or nothing) was needed to update
- return;
- }
-
- Vector<RD::Uniform> uniforms;
-
- {
- if (shader_data->ubo_size) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 0;
- u.ids.push_back(uniform_buffer);
- uniforms.push_back(u);
- }
-
- const RID *textures = texture_cache.ptrw();
- for (uint32_t i = 0; i < tex_uniform_count; i++) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1 + i;
- u.ids.push_back(textures[i]);
- uniforms.push_back(u);
- }
- }
-
- uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, RD::BARRIER_MASK_RASTER);
}
SceneShaderForwardMobile::MaterialData::~MaterialData() {
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- }
-
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- }
+ free_parameters_uniform_set(uniform_set);
}
RendererStorageRD::MaterialData *SceneShaderForwardMobile::_create_material_func(ShaderData *p_shader) {
@@ -584,10 +475,22 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
Vector<String> shader_versions;
shader_versions.push_back(""); // SHADER_VERSION_COLOR_PASS
shader_versions.push_back("\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); // !BAS! SHADER_VERSION_SHADOW_PASS, should probably change this to MODE_RENDER_SHADOW because we don't have a depth pass here...
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); // SHADER_VERSION_DEPTH_PASS_DP (maybe rename to SHADER_VERSION_SHADOW_PASS_DP?)
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_SHADOW_PASS, should probably change this to MODE_RENDER_SHADOW because we don't have a depth pass here...
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); // SHADER_VERSION_SHADOW_PASS_DP
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL
+
+ // multiview versions of our shaders
+ shader_versions.push_back("\n#define USE_MULTIVIEW\n"); // SHADER_VERSION_COLOR_PASS_MULTIVIEW
+ shader_versions.push_back("\n#define USE_MULTIVIEW\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW
+ shader_versions.push_back("\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_SHADOW_PASS_MULTIVIEW
+
shader.initialize(shader_versions, p_defines);
+
+ if (!RendererCompositorRD::singleton->is_xr_enabled()) {
+ shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_MULTIVIEW, false);
+ shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW, false);
+ shader.set_variant_enabled(SHADER_VERSION_SHADOW_PASS_MULTIVIEW, false);
+ }
}
storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs);
@@ -602,7 +505,7 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
actions.renames["INV_CAMERA_MATRIX"] = "scene_data.inv_camera_matrix";
actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix";
actions.renames["PROJECTION_MATRIX"] = "projection_matrix";
- actions.renames["INV_PROJECTION_MATRIX"] = "scene_data.inv_projection_matrix";
+ actions.renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix";
actions.renames["MODELVIEW_MATRIX"] = "modelview";
actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal";
@@ -625,6 +528,9 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
//builtins
actions.renames["TIME"] = "scene_data.time";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size";
actions.renames["FRAGCOORD"] = "gl_FragCoord";
@@ -645,7 +551,6 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
actions.renames["SSS_STRENGTH"] = "sss_strength";
actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color";
actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth";
- actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve";
actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost";
actions.renames["BACKLIGHT"] = "backlight";
actions.renames["AO"] = "ao";
@@ -668,6 +573,11 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
actions.renames["CUSTOM1"] = "custom1_attrib";
actions.renames["CUSTOM2"] = "custom2_attrib";
actions.renames["CUSTOM3"] = "custom3_attrib";
+ actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+
+ actions.renames["VIEW_INDEX"] = "ViewIndex";
+ actions.renames["VIEW_MONO_LEFT"] = "0";
+ actions.renames["VIEW_RIGHT"] = "1";
//for light
actions.renames["VIEW"] = "view";
@@ -693,10 +603,10 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
actions.usage_defines["UV2"] = "#define UV2_USED\n";
actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";
actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n";
- actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n";
- actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n";
- actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n";
- actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n";
+ actions.usage_defines["CUSTOM0"] = "#define CUSTOM0_USED\n";
+ actions.usage_defines["CUSTOM1"] = "#define CUSTOM1_USED\n";
+ actions.usage_defines["CUSTOM2"] = "#define CUSTOM2_USED\n";
+ actions.usage_defines["CUSTOM3"] = "#define CUSTOM3_USED\n";
actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP";
actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
@@ -727,13 +637,13 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
actions.render_mode_defines["particle_trails"] = "#define USE_PARTICLE_TRAILS\n";
+ actions.render_mode_defines["depth_draw_opaque"] = "#define USE_OPAQUE_PREPASS\n";
bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley");
if (!force_lambert) {
actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
}
- actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
@@ -766,6 +676,8 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
actions.global_buffer_array_variable = "global_variables.data";
actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs";
+ actions.apply_luminance_multiplier = true; // apply luminance multiplier to screen texture
+
compiler.initialize(actions);
}
@@ -773,29 +685,55 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
//default material and shader
default_shader = storage->shader_allocate();
storage->shader_initialize(default_shader);
- storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n");
+ storage->shader_set_code(default_shader, R"(
+// Default 3D material shader (mobile).
+
+shader_type spatial;
+
+void vertex() {
+ ROUGHNESS = 0.8;
+}
+
+void fragment() {
+ ALBEDO = vec3(0.6);
+ ROUGHNESS = 0.8;
+ METALLIC = 0.2;
+}
+)");
default_material = storage->material_allocate();
storage->material_initialize(default_material);
storage->material_set_shader(default_material, default_shader);
MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS);
+
+ default_material_shader_ptr = md->shader_data;
+ default_material_uniform_set = md->uniform_set;
}
{
overdraw_material_shader = storage->shader_allocate();
storage->shader_initialize(overdraw_material_shader);
- storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }");
+ // Use relatively low opacity so that more "layers" of overlapping objects can be distinguished.
+ storage->shader_set_code(overdraw_material_shader, R"(
+// 3D editor Overdraw debug draw mode shader (mobile).
+
+shader_type spatial;
+
+render_mode blend_add, unshaded;
+
+void fragment() {
+ ALBEDO = vec3(0.4, 0.8, 0.8);
+ ALPHA = 0.1;
+}
+)");
overdraw_material = storage->material_allocate();
storage->material_initialize(overdraw_material);
storage->material_set_shader(overdraw_material, overdraw_material_shader);
- wireframe_material_shader = storage->shader_allocate();
- storage->shader_initialize(wireframe_material_shader);
- storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }");
- wireframe_material = storage->material_allocate();
- storage->material_initialize(wireframe_material);
- storage->material_set_shader(wireframe_material, wireframe_material_shader);
+ MaterialData *md = (MaterialData *)storage->material_get_data(overdraw_material, RendererStorageRD::SHADER_TYPE_3D);
+ overdraw_material_shader_ptr = md->shader_data;
+ overdraw_material_uniform_set = md->uniform_set;
}
{
@@ -819,15 +757,26 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
}
}
+void SceneShaderForwardMobile::set_default_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_constants) {
+ default_specialization_constants = p_constants;
+ for (SelfList<ShaderData> *E = shader_list.first(); E; E = E->next()) {
+ for (int i = 0; i < ShaderData::CULL_VARIANT_MAX; i++) {
+ for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
+ for (int k = 0; k < SHADER_VERSION_MAX; k++) {
+ E->self()->pipelines[i][j][k].update_specialization_constants(default_specialization_constants);
+ }
+ }
+ }
+ }
+}
+
SceneShaderForwardMobile::~SceneShaderForwardMobile() {
RD::get_singleton()->free(default_vec4_xform_buffer);
RD::get_singleton()->free(shadow_sampler);
- storage->free(wireframe_material_shader);
storage->free(overdraw_material_shader);
storage->free(default_shader);
- storage->free(wireframe_material);
storage->free(overdraw_material);
storage->free(default_material);
}
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
index 1517197d25..392fac1e3e 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -47,8 +47,13 @@ public:
SHADER_VERSION_COLOR_PASS,
SHADER_VERSION_LIGHTMAP_COLOR_PASS,
SHADER_VERSION_SHADOW_PASS,
- SHADER_VERSION_DEPTH_PASS_DP,
+ SHADER_VERSION_SHADOW_PASS_DP,
SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
+
+ SHADER_VERSION_COLOR_PASS_MULTIVIEW,
+ SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW,
+ SHADER_VERSION_SHADOW_PASS_MULTIVIEW,
+
SHADER_VERSION_MAX
};
@@ -106,7 +111,7 @@ public:
uint32_t ubo_size;
String code;
- Map<StringName, RID> default_texture_params;
+ Map<StringName, Map<int, RID>> default_texture_params;
DepthDraw depth_draw;
DepthTest depth_test;
@@ -136,7 +141,7 @@ public:
uint32_t index = 0;
virtual void set_code(const String &p_Code);
- virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
@@ -146,6 +151,8 @@ public:
virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+ SelfList<ShaderData> shader_list_element;
+
ShaderData();
virtual ~ShaderData();
};
@@ -158,20 +165,19 @@ public:
struct MaterialData : public RendererStorageRD::MaterialData {
uint64_t last_frame;
ShaderData *shader_data;
- RID uniform_buffer;
RID uniform_set;
- Vector<RID> texture_cache;
- Vector<uint8_t> ubo_data;
uint64_t last_pass = 0;
uint32_t index = 0;
RID next_pass;
uint8_t priority;
virtual void set_render_priority(int p_priority);
virtual void set_next_pass(RID p_pass);
- virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual ~MaterialData();
};
+ SelfList<ShaderData>::List shader_list;
+
RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) {
return static_cast<SceneShaderForwardMobile *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
@@ -184,8 +190,6 @@ public:
RID default_material;
RID overdraw_material_shader;
RID overdraw_material;
- RID wireframe_material_shader;
- RID wireframe_material;
RID default_shader_rd;
RID default_vec4_xform_buffer;
@@ -193,10 +197,19 @@ public:
RID shadow_sampler;
+ RID default_material_uniform_set;
+ ShaderData *default_material_shader_ptr = nullptr;
+
+ RID overdraw_material_uniform_set;
+ ShaderData *overdraw_material_shader_ptr = nullptr;
+
SceneShaderForwardMobile();
~SceneShaderForwardMobile();
+ Vector<RD::PipelineSpecializationConstant> default_specialization_constants;
+
void init(RendererStorageRD *p_storage, const String p_defines);
+ void set_default_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_constants);
};
} // namespace RendererSceneRenderImplementation
diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp
index b2b919c40e..0d60052666 100644
--- a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp
+++ b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp
@@ -31,25 +31,48 @@
#include "pipeline_cache_rd.h"
#include "core/os/memory.h"
-RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe) {
+RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe, uint32_t p_render_pass, uint32_t p_bool_specializations) {
RD::PipelineMultisampleState multisample_state_version = multisample_state;
- multisample_state_version.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_framebuffer_format_id);
+ multisample_state_version.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_framebuffer_format_id, p_render_pass);
+
+ bool wireframe = p_wireframe || rasterization_state.wireframe;
RD::PipelineRasterizationState raster_state_version = rasterization_state;
- raster_state_version.wireframe = p_wireframe;
+ raster_state_version.wireframe = wireframe;
+
+ Vector<RD::PipelineSpecializationConstant> specialization_constants = base_specialization_constants;
- RID pipeline = RD::get_singleton()->render_pipeline_create(shader, p_framebuffer_format_id, p_vertex_format_id, render_primitive, raster_state_version, multisample_state_version, depth_stencil_state, blend_state, dynamic_state_flags);
+ uint32_t bool_index = 0;
+ uint32_t bool_specializations = p_bool_specializations;
+ while (bool_specializations) {
+ if (bool_specializations & (1 << bool_index)) {
+ RD::PipelineSpecializationConstant sc;
+ sc.bool_value = true;
+ sc.constant_id = bool_index;
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
+ specialization_constants.push_back(sc);
+ bool_specializations &= ~(1 << bool_index);
+ }
+ bool_index++;
+ }
+
+ RID pipeline = RD::get_singleton()->render_pipeline_create(shader, p_framebuffer_format_id, p_vertex_format_id, render_primitive, raster_state_version, multisample_state_version, depth_stencil_state, blend_state, dynamic_state_flags, p_render_pass, specialization_constants);
ERR_FAIL_COND_V(pipeline.is_null(), RID());
versions = (Version *)memrealloc(versions, sizeof(Version) * (version_count + 1));
versions[version_count].framebuffer_id = p_framebuffer_format_id;
versions[version_count].vertex_id = p_vertex_format_id;
- versions[version_count].wireframe = p_wireframe;
+ versions[version_count].wireframe = wireframe;
versions[version_count].pipeline = pipeline;
+ versions[version_count].render_pass = p_render_pass;
+ versions[version_count].bool_specializations = p_bool_specializations;
version_count++;
return pipeline;
}
void PipelineCacheRD::_clear() {
+#ifndef _MSC_VER
+#warning Clear should probably recompile all the variants already compiled instead to avoid stalls? needs discussion
+#endif
if (versions) {
for (uint32_t i = 0; i < version_count; i++) {
//shader may be gone, so this may not be valid
@@ -63,7 +86,7 @@ void PipelineCacheRD::_clear() {
}
}
-void PipelineCacheRD::setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags) {
+void PipelineCacheRD::setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags, const Vector<RD::PipelineSpecializationConstant> &p_base_specialization_constants) {
ERR_FAIL_COND(p_shader.is_null());
_clear();
shader = p_shader;
@@ -74,6 +97,11 @@ void PipelineCacheRD::setup(RID p_shader, RD::RenderPrimitive p_primitive, const
depth_stencil_state = p_depth_stencil_state;
blend_state = p_blend_state;
dynamic_state_flags = p_dynamic_state_flags;
+ base_specialization_constants = p_base_specialization_constants;
+}
+void PipelineCacheRD::update_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_base_specialization_constants) {
+ base_specialization_constants = p_base_specialization_constants;
+ _clear();
}
void PipelineCacheRD::update_shader(RID p_shader) {
diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.h b/servers/rendering/renderer_rd/pipeline_cache_rd.h
index b1c8f21ecc..e52f47fa47 100644
--- a/servers/rendering/renderer_rd/pipeline_cache_rd.h
+++ b/servers/rendering/renderer_rd/pipeline_cache_rd.h
@@ -46,26 +46,30 @@ class PipelineCacheRD {
RD::PipelineDepthStencilState depth_stencil_state;
RD::PipelineColorBlendState blend_state;
int dynamic_state_flags;
+ Vector<RD::PipelineSpecializationConstant> base_specialization_constants;
struct Version {
RD::VertexFormatID vertex_id;
RD::FramebufferFormatID framebuffer_id;
+ uint32_t render_pass;
bool wireframe;
+ uint32_t bool_specializations;
RID pipeline;
};
Version *versions;
uint32_t version_count;
- RID _generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe);
+ RID _generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe, uint32_t p_render_pass, uint32_t p_bool_specializations = 0);
void _clear();
public:
- void setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0);
+ void setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, const Vector<RD::PipelineSpecializationConstant> &p_base_specialization_constants = Vector<RD::PipelineSpecializationConstant>());
+ void update_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_base_specialization_constants);
void update_shader(RID p_shader);
- _FORCE_INLINE_ RID get_render_pipeline(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe = false) {
+ _FORCE_INLINE_ RID get_render_pipeline(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe = false, uint32_t p_render_pass = 0, uint32_t p_bool_specializations = 0) {
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_V_MSG(shader.is_null(), RID(),
"Attempted to use an unused shader variant (shader is null),");
@@ -74,13 +78,13 @@ public:
spin_lock.lock();
RID result;
for (uint32_t i = 0; i < version_count; i++) {
- if (versions[i].vertex_id == p_vertex_format_id && versions[i].framebuffer_id == p_framebuffer_format_id && versions[i].wireframe == p_wireframe) {
+ if (versions[i].vertex_id == p_vertex_format_id && versions[i].framebuffer_id == p_framebuffer_format_id && versions[i].wireframe == p_wireframe && versions[i].render_pass == p_render_pass && versions[i].bool_specializations == p_bool_specializations) {
result = versions[i].pipeline;
spin_lock.unlock();
return result;
}
}
- result = _generate_version(p_vertex_format_id, p_framebuffer_format_id, p_wireframe);
+ result = _generate_version(p_vertex_format_id, p_framebuffer_format_id, p_wireframe, p_render_pass, p_bool_specializations);
spin_lock.unlock();
return result;
}
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index f448698976..d013099cce 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -29,10 +29,13 @@
/*************************************************************************/
#include "renderer_canvas_render_rd.h"
+
#include "core/config/project_settings.h"
#include "core/math/geometry_2d.h"
+#include "core/math/math_defs.h"
#include "core/math/math_funcs.h"
#include "renderer_compositor_rd.h"
+#include "servers/rendering/rendering_server_default.h"
void RendererCanvasRenderRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) {
p_mat4[0] = p_transform.elements[0][0];
@@ -74,7 +77,7 @@ void RendererCanvasRenderRD::_update_transform_2d_to_mat2x3(const Transform2D &p
p_mat2x3[5] = p_transform.elements[2][1];
}
-void RendererCanvasRenderRD::_update_transform_to_mat4(const Transform &p_transform, float *p_mat4) {
+void RendererCanvasRenderRD::_update_transform_to_mat4(const Transform3D &p_transform, float *p_mat4) {
p_mat4[0] = p_transform.basis.elements[0][0];
p_mat4[1] = p_transform.basis.elements[1][0];
p_mat4[2] = p_transform.basis.elements[2][0];
@@ -390,7 +393,7 @@ void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RI
r_last_texture = p_texture;
}
-void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) {
+void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) {
//create an empty push constant
RS::CanvasItemTextureFilter current_filter = default_filter;
@@ -406,6 +409,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
PushConstant push_constant;
Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;
+ Transform2D draw_transform;
_update_transform_2d_to_mat2x3(base_transform, push_constant.world);
Color base_color = p_item->final_modulate;
@@ -462,14 +466,25 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
RID last_texture;
Size2 texpixel_size;
+ bool skipping = false;
+
const Item::Command *c = p_item->commands;
while (c) {
+ if (skipping && c->type != Item::Command::TYPE_ANIMATION_SLICE) {
+ c = c->next;
+ continue;
+ }
+
push_constant.flags = base_flags | (push_constant.flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config
switch (c->type) {
case Item::Command::TYPE_RECT: {
const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c);
+ if (rect->flags & CANVAS_RECT_TILE) {
+ current_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED;
+ }
+
//bind pipeline
{
RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
@@ -527,6 +542,14 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
src_rect = Rect2(0, 0, 1, 1);
}
+ if (rect->flags & CANVAS_RECT_MSDF) {
+ push_constant.flags |= FLAGS_USE_MSDF;
+ push_constant.msdf[0] = rect->px_range; // Pixel range.
+ push_constant.msdf[1] = rect->outline; // Outline size.
+ push_constant.msdf[2] = 0.f; // Reserved.
+ push_constant.msdf[3] = 0.f; // Reserved.
+ }
+
push_constant.modulation[0] = rect->modulate.r * base_color.r;
push_constant.modulation[1] = rect->modulate.g * base_color.g;
push_constant.modulation[2] = rect->modulate.b * base_color.b;
@@ -610,7 +633,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
RD::get_singleton()->draw_list_draw(p_draw_list, true);
- //restore if overrided
+ // Restore if overridden.
push_constant.color_texture_pixel_size[0] = texpixel_size.x;
push_constant.color_texture_pixel_size[1] = texpixel_size.y;
@@ -722,7 +745,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
mesh_instance = m->mesh_instance;
texture = m->texture;
modulate = m->modulate;
- _update_transform_2d_to_mat2x3(base_transform * m->transform, push_constant.world);
+ _update_transform_2d_to_mat2x3(base_transform * draw_transform * m->transform, push_constant.world);
} else if (c->type == Item::Command::TYPE_MULTIMESH) {
const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
RID multimesh = mm->multimesh;
@@ -735,6 +758,10 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
instance_count = storage->multimesh_get_instances_to_draw(multimesh);
+ if (instance_count == 0) {
+ break;
+ }
+
RID uniform_set = storage->multimesh_get_2d_uniform_set(multimesh, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET);
RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, TRANSFORMS_UNIFORM_SET);
push_constant.flags |= 1; //multimesh, trails disabled
@@ -747,9 +774,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
} else if (c->type == Item::Command::TYPE_PARTICLES) {
const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c);
ERR_BREAK(storage->particles_get_mode(pt->particles) != RS::PARTICLES_MODE_2D);
+ storage->particles_request_process(pt->particles);
+
if (storage->particles_is_inactive(pt->particles)) {
break;
}
+
+ RenderingServerDefault::redraw_request(); // active particles means redraw request
+
+ bool local_coords = true;
int dpc = storage->particles_get_draw_passes(pt->particles);
if (dpc == 0) {
break; //nothing to draw
@@ -768,6 +801,30 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
mesh = storage->particles_get_draw_pass_mesh(pt->particles, 0); //higher ones are ignored
texture = pt->texture;
+
+ if (storage->particles_has_collision(pt->particles) && storage->render_target_is_sdf_enabled(p_render_target)) {
+ //pass collision information
+ Transform2D xform;
+ if (local_coords) {
+ xform = p_item->final_transform;
+ } else {
+ xform = p_canvas_transform_inverse;
+ }
+
+ RID sdf_texture = storage->render_target_get_sdf_texture(p_render_target);
+
+ Rect2 to_screen;
+ {
+ Rect2 sdf_rect = storage->render_target_get_sdf_rect(p_render_target);
+
+ to_screen.size = Vector2(1.0 / sdf_rect.size.width, 1.0 / sdf_rect.size.height);
+ to_screen.position = -sdf_rect.position * to_screen.size;
+ }
+
+ storage->particles_set_canvas_sdf_collision(pt->particles, true, xform, to_screen, sdf_texture);
+ } else {
+ storage->particles_set_canvas_sdf_collision(pt->particles, false, Transform2D(), Rect2(), RID());
+ }
}
if (mesh.is_null()) {
@@ -825,10 +882,10 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
for (int j = 0; j < 6; j++) {
push_constant.world[j] = world_backup[j];
}
-
} break;
case Item::Command::TYPE_TRANSFORM: {
const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
+ draw_transform = transform->xform;
_update_transform_2d_to_mat2x3(base_transform * transform->xform, push_constant.world);
} break;
@@ -847,6 +904,14 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
}
} break;
+ case Item::Command::TYPE_ANIMATION_SLICE: {
+ const Item::CommandAnimationSlice *as = static_cast<const Item::CommandAnimationSlice *>(c);
+ double current_time = RendererCompositorRD::singleton->get_total_time();
+ double local_time = Math::fposmod(current_time - as->offset, as->animation_length);
+ skipping = !(local_time >= as->slice_begin && local_time < as->slice_end);
+
+ RenderingServerDefault::redraw_request(); // animation visible means redraw request
+ } break;
}
c = c->next;
@@ -1026,7 +1091,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
}
}
- RID material = ci->material;
+ RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material;
if (material.is_null() && ci->canvas_group != nullptr) {
material = default_canvas_group_material;
@@ -1041,7 +1106,8 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
if (material_data) {
if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) {
pipeline_variants = &material_data->shader_data->pipeline_variants;
- if (material_data->uniform_set.is_valid()) {
+ // Update uniform set.
+ if (material_data->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material_data->uniform_set)) { // Material may not have a uniform set.
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, MATERIAL_UNIFORM_SET);
}
} else {
@@ -1052,7 +1118,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
}
}
- _render_item(draw_list, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants);
+ _render_item(draw_list, p_to_render_target, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants);
prev_material = material;
}
@@ -1083,7 +1149,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
continue;
}
- CanvasLight *clight = canvas_light_owner.getornull(l->light_internal);
+ CanvasLight *clight = canvas_light_owner.get_or_null(l->light_internal);
if (!clight) { //unused or invalid texture
l->render_index_cache = -1;
l = l->next_ptr;
@@ -1146,7 +1212,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
continue;
}
- CanvasLight *clight = canvas_light_owner.getornull(l->light_internal);
+ CanvasLight *clight = canvas_light_owner.get_or_null(l->light_internal);
if (!clight) { //unused or invalid texture
l->render_index_cache = -1;
l = l->next_ptr;
@@ -1218,7 +1284,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
Size2i ssize = storage->render_target_get_size(p_to_render_target);
- Transform screen_transform;
+ Transform3D screen_transform;
screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f);
screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f));
_update_transform_to_mat4(screen_transform, state_buffer.screen_transform);
@@ -1280,6 +1346,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
Item *canvas_group_owner = nullptr;
bool update_skeletons = false;
+ bool time_used = false;
while (ci) {
if (ci->copy_back_buffer && canvas_group_owner == nullptr) {
@@ -1292,8 +1359,10 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
}
}
- if (ci->material.is_valid()) {
- MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RendererStorageRD::SHADER_TYPE_2D);
+ RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material;
+
+ if (material.is_valid()) {
+ MaterialData *md = (MaterialData *)storage->material_get_data(material, RendererStorageRD::SHADER_TYPE_2D);
if (md && md->shader_data->valid) {
if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) {
if (!material_screen_texture_found) {
@@ -1305,12 +1374,15 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
if (md->shader_data->uses_sdf) {
r_sdf_used = true;
}
+ if (md->shader_data->uses_time) {
+ time_used = true;
+ }
if (md->last_frame != RendererCompositorRD::singleton->get_frame_number()) {
md->last_frame = RendererCompositorRD::singleton->get_frame_number();
if (!RD::get_singleton()->uniform_set_is_valid(md->uniform_set)) {
// uniform set may be gone because a dependency was erased. In this case, it will happen
// if a texture is deleted, so just re-create it.
- storage->material_force_update_textures(ci->material, RendererStorageRD::SHADER_TYPE_2D);
+ storage->material_force_update_textures(material, RendererStorageRD::SHADER_TYPE_2D);
}
}
}
@@ -1327,6 +1399,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
update_skeletons = true;
}
}
+ c = c->next;
}
}
@@ -1401,6 +1474,10 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
ci = ci->next;
}
+
+ if (time_used) {
+ RenderingServerDefault::redraw_request();
+ }
}
RID RendererCanvasRenderRD::light_create() {
@@ -1409,7 +1486,7 @@ RID RendererCanvasRenderRD::light_create() {
}
void RendererCanvasRenderRD::light_set_texture(RID p_rid, RID p_texture) {
- CanvasLight *cl = canvas_light_owner.getornull(p_rid);
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
ERR_FAIL_COND(!cl);
if (cl->texture == p_texture) {
return;
@@ -1425,7 +1502,7 @@ void RendererCanvasRenderRD::light_set_texture(RID p_rid, RID p_texture) {
}
void RendererCanvasRenderRD::light_set_use_shadow(RID p_rid, bool p_enable) {
- CanvasLight *cl = canvas_light_owner.getornull(p_rid);
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
ERR_FAIL_COND(!cl);
cl->shadow.enabled = p_enable;
@@ -1465,7 +1542,7 @@ void RendererCanvasRenderRD::_update_shadow_atlas() {
}
}
void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) {
- CanvasLight *cl = canvas_light_owner.getornull(p_rid);
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
ERR_FAIL_COND(!cl->shadow.enabled);
_update_shadow_atlas();
@@ -1499,7 +1576,7 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index,
}
Vector3 cam_target = Basis(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0));
- projection = projection * CameraMatrix(Transform().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse());
+ projection = projection * CameraMatrix(Transform3D().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse());
ShadowRenderPushConstant push_constant;
for (int y = 0; y < 4; y++) {
@@ -1513,13 +1590,10 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index,
push_constant.z_far = p_far;
push_constant.pad = 0;
- /*if (i == 0)
- *p_xform_cache = projection;*/
-
LightOccluderInstance *instance = p_occluders;
while (instance) {
- OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder);
+ OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder);
if (!co || co->index_array.is_null() || !(p_light_mask & instance->light_mask)) {
instance = instance->next;
@@ -1543,14 +1617,14 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index,
}
void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) {
- CanvasLight *cl = canvas_light_owner.getornull(p_rid);
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
ERR_FAIL_COND(!cl->shadow.enabled);
_update_shadow_atlas();
Vector2 light_dir = p_light_xform.elements[1].normalized();
- Vector2 center = p_clip_rect.position + p_clip_rect.size * 0.5;
+ Vector2 center = p_clip_rect.get_center();
float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(light_dir)) - light_dir.dot(center));
@@ -1577,7 +1651,7 @@ void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_sh
CameraMatrix projection;
projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance);
- projection = projection * CameraMatrix(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, -1)).affine_inverse());
+ projection = projection * CameraMatrix(Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, -1)).affine_inverse());
ShadowRenderPushConstant push_constant;
for (int y = 0; y < 4; y++) {
@@ -1594,7 +1668,7 @@ void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_sh
LightOccluderInstance *instance = p_occluders;
while (instance) {
- OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder);
+ OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder);
if (!co || co->index_array.is_null() || !(p_light_mask & instance->light_mask)) {
instance = instance->next;
@@ -1660,7 +1734,7 @@ void RendererCanvasRenderRD::render_sdf(RID p_render_target, LightOccluderInstan
LightOccluderInstance *instance = p_occluders;
while (instance) {
- OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder);
+ OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder);
if (!co || co->sdf_index_array.is_null()) {
instance = instance->next;
@@ -1694,7 +1768,7 @@ RID RendererCanvasRenderRD::occluder_polygon_create() {
}
void RendererCanvasRenderRD::occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) {
- OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder);
+ OccluderPolygon *oc = occluder_polygon_owner.get_or_null(p_occluder);
ERR_FAIL_COND(!oc);
Vector<Vector2> lines;
@@ -1863,7 +1937,7 @@ void RendererCanvasRenderRD::occluder_polygon_set_shape(RID p_occluder, const Ve
}
void RendererCanvasRenderRD::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) {
- OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder);
+ OccluderPolygon *oc = occluder_polygon_owner.get_or_null(p_occluder);
ERR_FAIL_COND(!oc);
oc->cull_mode = p_mode;
}
@@ -1877,6 +1951,7 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) {
uniforms.clear();
uses_screen_texture = false;
uses_sdf = false;
+ uses_time = false;
if (code == String()) {
return; //just invalid, but no error
@@ -1901,14 +1976,14 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) {
actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
actions.usage_flag_pointers["texture_sdf"] = &uses_sdf;
+ actions.usage_flag_pointers["TIME"] = &uses_time;
actions.uniforms = &uniforms;
RendererCanvasRenderRD *canvas_singleton = (RendererCanvasRenderRD *)RendererCanvasRender::singleton;
Error err = canvas_singleton->shader.compiler.compile(RS::SHADER_CANVAS_ITEM, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = canvas_singleton->shader.canvas_shader.version_create();
@@ -2049,46 +2124,55 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) {
valid = true;
}
-void RendererCanvasRenderRD::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+void RendererCanvasRenderRD::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
- default_texture_params.erase(p_name);
+ if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
+ default_texture_params[p_name].erase(p_index);
+
+ if (default_texture_params[p_name].is_empty()) {
+ default_texture_params.erase(p_name);
+ }
+ }
} else {
- default_texture_params[p_name] = p_texture;
+ if (!default_texture_params.has(p_name)) {
+ default_texture_params[p_name] = Map<int, RID>();
+ }
+ default_texture_params[p_name][p_index] = p_texture;
}
}
void RendererCanvasRenderRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
Map<int, StringName> order;
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
continue;
}
- if (E->get().texture_order >= 0) {
- order[E->get().texture_order + 100000] = E->key();
+ if (E.value.texture_order >= 0) {
+ order[E.value.texture_order + 100000] = E.key;
} else {
- order[E->get().order] = E->key();
+ order[E.value.order] = E.key;
}
}
- for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
- pi.name = E->get();
+ for (const KeyValue<int, StringName> &E : order) {
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
+ pi.name = E.value;
p_param_list->push_back(pi);
}
}
void RendererCanvasRenderRD::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
RendererStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E->get());
- p.info.name = E->key(); //supply name
- p.index = E->get().instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+ p.info = ShaderLanguage::uniform_to_property_info(E.value);
+ p.info.name = E.key; //supply name
+ p.index = E.value.instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
p_param_list->push_back(p);
}
}
@@ -2113,7 +2197,7 @@ Variant RendererCanvasRenderRD::ShaderData::get_default_parameter(const StringNa
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
return Variant();
}
@@ -2143,94 +2227,14 @@ RendererStorageRD::ShaderData *RendererCanvasRenderRD::_create_shader_func() {
return shader_data;
}
-void RendererCanvasRenderRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+bool RendererCanvasRenderRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
RendererCanvasRenderRD *canvas_singleton = (RendererCanvasRenderRD *)RendererCanvasRender::singleton;
- if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
- p_uniform_dirty = true;
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- uniform_buffer = RID();
- }
-
- ubo_data.resize(shader_data->ubo_size);
- if (ubo_data.size()) {
- uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
- memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
- }
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
-
- //check whether buffer changed
- if (p_uniform_dirty && ubo_data.size()) {
- update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
- RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw());
- }
-
- uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
-
- if ((uint32_t)texture_cache.size() != tex_uniform_count) {
- texture_cache.resize(tex_uniform_count);
- p_textures_dirty = true;
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
-
- if (p_textures_dirty && tex_uniform_count) {
- update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), false);
- }
-
- if (shader_data->ubo_size == 0) {
- // This material does not require an uniform set, so don't create it.
- return;
- }
-
- if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- //no reason to update uniform set, only UBO (or nothing) was needed to update
- return;
- }
-
- Vector<RD::Uniform> uniforms;
-
- {
- if (shader_data->ubo_size) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 0;
- u.ids.push_back(uniform_buffer);
- uniforms.push_back(u);
- }
-
- const RID *textures = texture_cache.ptrw();
- for (uint32_t i = 0; i < tex_uniform_count; i++) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1 + i;
- u.ids.push_back(textures[i]);
- uniforms.push_back(u);
- }
- }
-
- uniform_set = RD::get_singleton()->uniform_set_create(uniforms, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET);
}
RendererCanvasRenderRD::MaterialData::~MaterialData() {
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- }
-
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- }
+ free_parameters_uniform_set(uniform_set);
}
RendererStorageRD::MaterialData *RendererCanvasRenderRD::_create_material_func(ShaderData *p_shader) {
@@ -2367,6 +2371,9 @@ RendererCanvasRenderRD::RendererCanvasRenderRD(RendererStorageRD *p_storage) {
actions.renames["CANVAS_MATRIX"] = "canvas_data.canvas_transform";
actions.renames["SCREEN_MATRIX"] = "canvas_data.screen_transform";
actions.renames["TIME"] = "canvas_data.time";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
actions.renames["AT_LIGHT_PASS"] = "false";
actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
@@ -2589,8 +2596,21 @@ RendererCanvasRenderRD::RendererCanvasRenderRD(RendererStorageRD *p_storage) {
default_canvas_group_shader = storage->shader_allocate();
storage->shader_initialize(default_canvas_group_shader);
- storage->shader_set_code(default_canvas_group_shader, "shader_type canvas_item; \nvoid fragment() {\n\tvec4 c = textureLod(SCREEN_TEXTURE,SCREEN_UV,0.0); if (c.a > 0.0001) c.rgb/=c.a; COLOR *= c; \n}\n");
+ storage->shader_set_code(default_canvas_group_shader, R"(
+// Default CanvasGroup shader.
+shader_type canvas_item;
+
+void fragment() {
+ vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+
+ if (c.a > 0.0001) {
+ c.rgb /= c.a;
+ }
+
+ COLOR *= c;
+}
+)");
default_canvas_group_material = storage->material_allocate();
storage->material_initialize(default_canvas_group_material);
@@ -2602,7 +2622,7 @@ RendererCanvasRenderRD::RendererCanvasRenderRD(RendererStorageRD *p_storage) {
bool RendererCanvasRenderRD::free(RID p_rid) {
if (canvas_light_owner.owns(p_rid)) {
- CanvasLight *cl = canvas_light_owner.getornull(p_rid);
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
ERR_FAIL_COND_V(!cl, false);
light_set_use_shadow(p_rid, false);
canvas_light_owner.free(p_rid);
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 8129cc6c9b..26ccbd3bf5 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -84,8 +84,9 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
FLAGS_LIGHT_COUNT_SHIFT = 20,
FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 26),
- FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 27)
+ FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 27),
+ FLAGS_USE_MSDF = (1 << 28),
};
enum {
@@ -172,13 +173,14 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
uint32_t ubo_size;
String code;
- Map<StringName, RID> default_texture_params;
+ Map<StringName, Map<int, RID>> default_texture_params;
bool uses_screen_texture = false;
bool uses_sdf = false;
+ bool uses_time = false;
virtual void set_code(const String &p_Code);
- virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
@@ -200,14 +202,11 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
struct MaterialData : public RendererStorageRD::MaterialData {
uint64_t last_frame;
ShaderData *shader_data;
- RID uniform_buffer;
RID uniform_set;
- Vector<RID> texture_cache;
- Vector<uint8_t> ubo_data;
virtual void set_render_priority(int p_priority) {}
virtual void set_next_pass(RID p_pass) {}
- virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual ~MaterialData();
};
@@ -390,7 +389,10 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
//rect
struct {
float modulation[4];
- float ninepatch_margins[4];
+ union {
+ float msdf[4];
+ float ninepatch_margins[4];
+ };
float dst_rect[4];
float src_rect[4];
float pad[2];
@@ -425,14 +427,14 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
RID _create_base_uniform_set(RID p_to_render_target, bool p_backbuffer);
inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size); //recursive, so regular inline used instead.
- void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants);
+ void _render_item(RenderingDevice::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants);
void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer = false);
_FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);
_FORCE_INLINE_ void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3);
_FORCE_INLINE_ void _update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4);
- _FORCE_INLINE_ void _update_transform_to_mat4(const Transform &p_transform, float *p_mat4);
+ _FORCE_INLINE_ void _update_transform_to_mat4(const Transform3D &p_transform, float *p_mat4);
void _update_shadow_atlas();
@@ -456,8 +458,6 @@ public:
void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) {}
- void draw_window_margins(int *p_margins, RID *p_margin_textures) {}
-
virtual void set_shadow_texture_size(int p_size);
void set_time(double p_time);
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index 0012ba9c27..522a8e8112 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -31,6 +31,7 @@
#include "renderer_compositor_rd.h"
#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
void RendererCompositorRD::prepare_for_blitting_render_targets() {
RD::get_singleton()->prepare_screen_for_drawing();
@@ -45,6 +46,8 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID
RID rd_texture = storage->texture_get_rd_texture(texture);
ERR_CONTINUE(rd_texture.is_null());
+ // TODO if keep_3d_linear was set when rendering to this render target we need to add a linear->sRGB conversion in.
+
if (!render_target_descriptors.has(rd_texture) || !RD::get_singleton()->uniform_set_is_valid(render_target_descriptors[rd_texture])) {
Vector<RD::Uniform> uniforms;
RD::Uniform u;
@@ -59,16 +62,19 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID
}
Size2 screen_size(RD::get_singleton()->screen_get_width(p_screen), RD::get_singleton()->screen_get_height(p_screen));
- BlitMode mode = p_render_targets[i].lens_distortion.apply ? BLIT_MODE_LENS : p_render_targets[i].multi_view.use_layer ? BLIT_MODE_USE_LAYER :
- BLIT_MODE_NORMAL;
+ BlitMode mode = p_render_targets[i].lens_distortion.apply ? BLIT_MODE_LENS : (p_render_targets[i].multi_view.use_layer ? BLIT_MODE_USE_LAYER : BLIT_MODE_NORMAL);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blit.pipelines[mode]);
RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_target_descriptors[rd_texture], 0);
- blit.push_constant.rect[0] = p_render_targets[i].rect.position.x / screen_size.width;
- blit.push_constant.rect[1] = p_render_targets[i].rect.position.y / screen_size.height;
- blit.push_constant.rect[2] = p_render_targets[i].rect.size.width / screen_size.width;
- blit.push_constant.rect[3] = p_render_targets[i].rect.size.height / screen_size.height;
+ blit.push_constant.src_rect[0] = p_render_targets[i].src_rect.position.x;
+ blit.push_constant.src_rect[1] = p_render_targets[i].src_rect.position.y;
+ blit.push_constant.src_rect[2] = p_render_targets[i].src_rect.size.width;
+ blit.push_constant.src_rect[3] = p_render_targets[i].src_rect.size.height;
+ blit.push_constant.dst_rect[0] = p_render_targets[i].dst_rect.position.x / screen_size.width;
+ blit.push_constant.dst_rect[1] = p_render_targets[i].dst_rect.position.y / screen_size.height;
+ blit.push_constant.dst_rect[2] = p_render_targets[i].dst_rect.size.width / screen_size.width;
+ blit.push_constant.dst_rect[3] = p_render_targets[i].dst_rect.size.height / screen_size.height;
blit.push_constant.layer = p_render_targets[i].multi_view.layer;
blit.push_constant.eye_center[0] = p_render_targets[i].lens_distortion.eye_center.x;
blit.push_constant.eye_center[1] = p_render_targets[i].lens_distortion.eye_center.y;
@@ -110,13 +116,14 @@ void RendererCompositorRD::initialize() {
blit_modes.push_back("\n");
blit_modes.push_back("\n#define USE_LAYER\n");
blit_modes.push_back("\n#define USE_LAYER\n#define APPLY_LENS_DISTORTION\n");
+ blit_modes.push_back("\n");
blit.shader.initialize(blit_modes);
blit.shader_version = blit.shader.version_create();
for (int i = 0; i < BLIT_MODE_MAX; i++) {
- blit.pipelines[i] = RD::get_singleton()->render_pipeline_create(blit.shader.version_get_shader(blit.shader_version, i), RD::get_singleton()->screen_get_framebuffer_format(), RD::INVALID_ID, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RenderingDevice::PipelineColorBlendState::create_disabled(), 0);
+ blit.pipelines[i] = RD::get_singleton()->render_pipeline_create(blit.shader.version_get_shader(blit.shader_version, i), RD::get_singleton()->screen_get_framebuffer_format(), RD::INVALID_ID, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), i == BLIT_MODE_NORMAL_ALPHA ? RenderingDevice::PipelineColorBlendState::create_blend() : RenderingDevice::PipelineColorBlendState::create_disabled(), 0);
}
//create index array for copy shader
@@ -152,22 +159,144 @@ void RendererCompositorRD::finalize() {
RD::get_singleton()->free(blit.sampler);
}
+void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) {
+ RD::get_singleton()->prepare_screen_for_drawing();
+
+ RID texture = storage->texture_allocate();
+ storage->texture_2d_initialize(texture, p_image);
+ RID rd_texture = storage->texture_get_rd_texture(texture);
+
+ RID uset;
+ {
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+ u.binding = 0;
+ u.ids.push_back(blit.sampler);
+ u.ids.push_back(rd_texture);
+ uniforms.push_back(u);
+ uset = RD::get_singleton()->uniform_set_create(uniforms, blit.shader.version_get_shader(blit.shader_version, BLIT_MODE_NORMAL), 0);
+ }
+
+ Size2 window_size = DisplayServer::get_singleton()->window_get_size();
+
+ Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height());
+ Rect2 screenrect;
+ if (p_scale) {
+ if (window_size.width > window_size.height) {
+ //scale horizontally
+ screenrect.size.y = window_size.height;
+ screenrect.size.x = imgrect.size.x * window_size.height / imgrect.size.y;
+ screenrect.position.x = (window_size.width - screenrect.size.x) / 2;
+
+ } else {
+ //scale vertically
+ screenrect.size.x = window_size.width;
+ screenrect.size.y = imgrect.size.y * window_size.width / imgrect.size.x;
+ screenrect.position.y = (window_size.height - screenrect.size.y) / 2;
+ }
+ } else {
+ screenrect = imgrect;
+ screenrect.position += ((window_size - screenrect.size) / 2.0).floor();
+ }
+
+ screenrect.position /= window_size;
+ screenrect.size /= window_size;
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(DisplayServer::MAIN_WINDOW_ID, p_color);
+
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blit.pipelines[BLIT_MODE_NORMAL_ALPHA]);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uset, 0);
+
+ blit.push_constant.src_rect[0] = 0.0;
+ blit.push_constant.src_rect[1] = 0.0;
+ blit.push_constant.src_rect[2] = 1.0;
+ blit.push_constant.src_rect[3] = 1.0;
+ blit.push_constant.dst_rect[0] = screenrect.position.x;
+ blit.push_constant.dst_rect[1] = screenrect.position.y;
+ blit.push_constant.dst_rect[2] = screenrect.size.width;
+ blit.push_constant.dst_rect[3] = screenrect.size.height;
+ blit.push_constant.layer = 0;
+ blit.push_constant.eye_center[0] = 0;
+ blit.push_constant.eye_center[1] = 0;
+ blit.push_constant.k1 = 0;
+ blit.push_constant.k2 = 0;
+ blit.push_constant.upscale = 1.0;
+ blit.push_constant.aspect_ratio = 1.0;
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &blit.push_constant, sizeof(BlitPushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+
+ RD::get_singleton()->draw_list_end();
+
+ RD::get_singleton()->swap_buffers();
+
+ storage->free(texture);
+}
+
RendererCompositorRD *RendererCompositorRD::singleton = nullptr;
RendererCompositorRD::RendererCompositorRD() {
+ {
+ String shader_cache_dir = Engine::get_singleton()->get_shader_cache_path();
+ if (shader_cache_dir == String()) {
+ shader_cache_dir = "user://";
+ }
+ DirAccessRef da = DirAccess::open(shader_cache_dir);
+ if (!da) {
+ ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir);
+ } else {
+ Error err = da->change_dir("shader_cache");
+ if (err != OK) {
+ err = da->make_dir("shader_cache");
+ }
+ if (err != OK) {
+ ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir);
+ } else {
+ shader_cache_dir = shader_cache_dir.plus_file("shader_cache");
+
+ bool shader_cache_enabled = GLOBAL_GET("rendering/shader_compiler/shader_cache/enabled");
+ if (!Engine::get_singleton()->is_editor_hint() && !shader_cache_enabled) {
+ shader_cache_dir = String(); //disable only if not editor
+ }
+
+ if (shader_cache_dir != String()) {
+ bool compress = GLOBAL_GET("rendering/shader_compiler/shader_cache/compress");
+ bool use_zstd = GLOBAL_GET("rendering/shader_compiler/shader_cache/use_zstd_compression");
+ bool strip_debug = GLOBAL_GET("rendering/shader_compiler/shader_cache/strip_debug");
+
+ ShaderRD::set_shader_cache_dir(shader_cache_dir);
+ ShaderRD::set_shader_cache_save_compressed(compress);
+ ShaderRD::set_shader_cache_save_compressed_zstd(use_zstd);
+ ShaderRD::set_shader_cache_save_debug(!strip_debug);
+ }
+ }
+ }
+ }
+
singleton = this;
time = 0;
storage = memnew(RendererStorageRD);
canvas = memnew(RendererCanvasRenderRD(storage));
- uint32_t back_end = GLOBAL_GET("rendering/vulkan/rendering/back_end");
+ back_end = (bool)(int)GLOBAL_GET("rendering/vulkan/rendering/back_end");
uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
- if (back_end == 1 || textures_per_stage < 48) {
+ if (back_end || textures_per_stage < 48) {
scene = memnew(RendererSceneRenderImplementation::RenderForwardMobile(storage));
- } else { // back_end == 0
+ } else { // back_end == false
// default to our high end renderer
scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage));
}
+
+ scene->init();
+
+ // now we're ready to create our effects,
+ storage->init_effects(!scene->_render_buffers_can_be_storage());
+}
+
+RendererCompositorRD::~RendererCompositorRD() {
+ ShaderRD::set_shader_cache_dir(String());
}
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index 52552f7ee3..f69e40e0ff 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -50,11 +50,13 @@ protected:
BLIT_MODE_NORMAL,
BLIT_MODE_USE_LAYER,
BLIT_MODE_LENS,
+ BLIT_MODE_NORMAL_ALPHA,
BLIT_MODE_MAX
};
struct BlitPushConstant {
- float rect[4];
+ float src_rect[4];
+ float dst_rect[4];
float eye_center[2];
float k1;
@@ -79,7 +81,7 @@ protected:
Map<RID, RID> render_target_descriptors;
double time;
- float delta;
+ double delta;
static uint64_t frame;
@@ -88,7 +90,7 @@ public:
RendererCanvasRender *get_canvas() { return canvas; }
RendererSceneRender *get_scene() { return scene; }
- void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) {}
+ void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter);
void initialize();
void begin_frame(double frame_step);
@@ -99,7 +101,7 @@ public:
void finalize();
_ALWAYS_INLINE_ uint64_t get_frame_number() const { return frame; }
- _ALWAYS_INLINE_ float get_frame_delta_time() const { return delta; }
+ _ALWAYS_INLINE_ double get_frame_delta_time() const { return delta; }
_ALWAYS_INLINE_ double get_total_time() const { return time; }
static Error is_viable() {
@@ -114,10 +116,8 @@ public:
_create_func = _create_current;
}
- virtual bool is_low_end() const { return false; }
-
static RendererCompositorRD *singleton;
RendererCompositorRD();
- ~RendererCompositorRD() {}
+ ~RendererCompositorRD();
};
#endif // RASTERIZER_RD_H
diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp
index d631cb4bac..550e59ba98 100644
--- a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp
@@ -32,13 +32,12 @@
uint64_t RendererSceneEnvironmentRD::auto_exposure_counter = 2;
-void RendererSceneEnvironmentRD::set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) {
+void RendererSceneEnvironmentRD::set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source) {
ambient_light = p_color;
ambient_source = p_ambient;
ambient_light_energy = p_energy;
ambient_sky_contribution = p_sky_contribution;
reflection_source = p_reflection_source;
- ao_color = p_ao_color;
}
void RendererSceneEnvironmentRD::set_tonemap(RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {
@@ -93,16 +92,19 @@ void RendererSceneEnvironmentRD::set_fog(bool p_enable, const Color &p_light_col
fog_aerial_perspective = p_fog_aerial_perspective;
}
-void RendererSceneEnvironmentRD::set_volumetric_fog(bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) {
+void RendererSceneEnvironmentRD::set_volumetric_fog(bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) {
volumetric_fog_enabled = p_enable;
volumetric_fog_density = p_density;
- volumetric_fog_light = p_light;
- volumetric_fog_light_energy = p_light_energy;
+ volumetric_fog_scattering = p_albedo;
+ volumetric_fog_emission = p_emission;
+ volumetric_fog_emission_energy = p_emission_energy;
+ volumetric_fog_anisotropy = p_anisotropy,
volumetric_fog_length = p_length;
volumetric_fog_detail_spread = p_detail_spread;
volumetric_fog_gi_inject = p_gi_inject;
volumetric_fog_temporal_reprojection = p_temporal_reprojection;
volumetric_fog_temporal_reprojection_amount = p_temporal_reprojection_amount;
+ volumetric_fog_ambient_inject = p_ambient_inject;
}
void RendererSceneEnvironmentRD::set_ssr(bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) {
diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h
index 992c4bf471..ec9cb4a798 100644
--- a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h
@@ -52,7 +52,6 @@ public:
float ambient_light_energy = 1.0;
float ambient_sky_contribution = 1.0;
RS::EnvironmentReflectionSource reflection_source = RS::ENV_REFLECTION_SOURCE_BG;
- Color ao_color;
/// Tonemap
@@ -80,13 +79,16 @@ public:
///
bool volumetric_fog_enabled = false;
float volumetric_fog_density = 0.01;
- Color volumetric_fog_light = Color(0, 0, 0);
- float volumetric_fog_light_energy = 0.0;
+ Color volumetric_fog_scattering = Color(1, 1, 1);
+ Color volumetric_fog_emission = Color(0, 0, 0);
+ float volumetric_fog_emission_energy = 0.0;
+ float volumetric_fog_anisotropy = 0.2;
float volumetric_fog_length = 64.0;
float volumetric_fog_detail_spread = 2.0;
float volumetric_fog_gi_inject = 0.0;
bool volumetric_fog_temporal_reprojection = true;
float volumetric_fog_temporal_reprojection_amount = 0.9;
+ float volumetric_fog_ambient_inject = 0.0;
/// Glow
@@ -142,12 +144,12 @@ public:
bool use_1d_color_correction = false;
RID color_correction = RID();
- void set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color);
+ void set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source);
void set_tonemap(RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale);
void set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap);
void set_sdfgi(bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias);
void set_fog(bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective);
- void set_volumetric_fog(bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount);
+ void set_volumetric_fog(bool p_enable, float p_density, const Color &p_scatterin, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject);
void set_ssr(bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance);
void set_ssao(bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect);
};
diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
index b289b17fad..b6b5c90b39 100644
--- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
@@ -1099,7 +1099,7 @@ void RendererSceneGIRD::SDFGI::update_cascades() {
RD::get_singleton()->buffer_update(cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, RD::BARRIER_MASK_COMPUTE);
}
-void RendererSceneGIRD::SDFGI::debug_draw(const CameraMatrix &p_projection, const Transform &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture) {
+void RendererSceneGIRD::SDFGI::debug_draw(const CameraMatrix &p_projection, const Transform3D &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture) {
if (!debug_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(debug_uniform_set)) {
Vector<RD::Uniform> uniforms;
{
@@ -1367,7 +1367,7 @@ void RendererSceneGIRD::SDFGI::debug_probes(RD::DrawListID p_draw_list, RID p_fr
}
}
-void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render) {
+void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render) {
/* Update general SDFGI Buffer */
SDFGIData sdfgi_data;
@@ -1450,7 +1450,7 @@ void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform &p_transform, Rend
break;
}
- RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_scene_render->render_state.sdfgi_update_data->directional_lights->get(j));
+ RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_scene_render->render_state.sdfgi_update_data->directional_lights->get(j));
ERR_CONTINUE(!li);
if (storage->light_directional_is_sky_only(li->light)) {
@@ -1469,7 +1469,7 @@ void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform &p_transform, Rend
lights[idx].color[1] = color.g;
lights[idx].color[2] = color.b;
lights[idx].type = RS::LIGHT_DIRECTIONAL;
- lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
+ lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
lights[idx].has_shadow = storage->light_has_shadow(li->light);
idx++;
@@ -1484,7 +1484,7 @@ void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform &p_transform, Rend
break;
}
- RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_scene_render->render_state.sdfgi_update_data->positional_light_instances[j]);
+ RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_scene_render->render_state.sdfgi_update_data->positional_light_instances[j]);
ERR_CONTINUE(!li);
uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light);
@@ -1514,7 +1514,7 @@ void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform &p_transform, Rend
lights[idx].color[1] = color.g;
lights[idx].color[2] = color.b;
lights[idx].type = storage->light_get_type(li->light);
- lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
+ lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
lights[idx].has_shadow = storage->light_has_shadow(li->light);
lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
@@ -1534,7 +1534,7 @@ void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform &p_transform, Rend
void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region, const PagedArray<RendererSceneRender::GeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render) {
//print_line("rendering region " + itos(p_region));
- RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers);
+ RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND(!rb); // we wouldn't be here if this failed but...
AABB bounds;
Vector3i from;
@@ -1862,7 +1862,7 @@ void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region,
#if 0
Vector<uint8_t> data = RD::get_singleton()->texture_get_data(cascades[cascade].sdf, 0);
Ref<Image> img;
- img.instance();
+ img.instantiate();
for (uint32_t i = 0; i < cascade_size; i++) {
Vector<uint8_t> subarr = data.subarray(128 * 128 * i, 128 * 128 * (i + 1) - 1);
img->create(cascade_size, cascade_size, false, Image::FORMAT_L8, subarr);
@@ -1875,7 +1875,7 @@ void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region,
#if 0
Vector<uint8_t> data = RD::get_singleton()->texture_get_data(render_albedo, 0);
Ref<Image> img;
- img.instance();
+ img.instantiate();
for (uint32_t i = 0; i < cascade_size; i++) {
Vector<uint8_t> subarr = data.subarray(128 * 128 * i * 2, 128 * 128 * (i + 1) * 2 - 1);
img->createcascade_size, cascade_size, false, Image::FORMAT_RGB565, subarr);
@@ -1892,7 +1892,7 @@ void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region,
}
void RendererSceneGIRD::SDFGI::render_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render) {
- RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers);
+ RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND(!rb); // we wouldn't be here if this failed but...
RD::get_singleton()->draw_command_begin_label("SDFGI Render Static Lighs");
@@ -1921,7 +1921,7 @@ void RendererSceneGIRD::SDFGI::render_static_lights(RID p_render_buffers, uint32
break;
}
- RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_positional_light_cull_result[i][j]);
+ RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_positional_light_cull_result[i][j]);
ERR_CONTINUE(!li);
uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light);
@@ -1953,7 +1953,7 @@ void RendererSceneGIRD::SDFGI::render_static_lights(RID p_render_buffers, uint32
lights[idx].color[0] = color.r;
lights[idx].color[1] = color.g;
lights[idx].color[2] = color.b;
- lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
+ lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
lights[idx].has_shadow = storage->light_has_shadow(li->light);
lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
@@ -2012,10 +2012,10 @@ void RendererSceneGIRD::SDFGI::render_static_lights(RID p_render_buffers, uint32
}
////////////////////////////////////////////////////////////////////////////////
-// GIProbeInstance
+// VoxelGIInstance
-void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
- uint32_t data_version = storage->gi_probe_get_data_version(probe);
+void RendererSceneGIRD::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
+ uint32_t data_version = storage->voxel_gi_get_data_version(probe);
// (RE)CREATE IF NEEDED
@@ -2034,11 +2034,11 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
dynamic_maps.clear();
- Vector3i octree_size = storage->gi_probe_get_octree_size(probe);
+ Vector3i octree_size = storage->voxel_gi_get_octree_size(probe);
if (octree_size != Vector3i()) {
//can create a 3D texture
- Vector<int> levels = storage->gi_probe_get_level_counts(probe);
+ Vector<int> levels = storage->voxel_gi_get_level_counts(probe);
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
@@ -2064,7 +2064,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
}
for (int i = 0; i < levels.size(); i++) {
- GIProbeInstance::Mipmap mipmap;
+ VoxelGIInstance::Mipmap mipmap;
mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), texture, 0, i, RD::TEXTURE_SLICE_3D);
mipmap.level = levels.size() - i - 1;
mipmap.cell_offset = 0;
@@ -2078,14 +2078,14 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 1;
- u.ids.push_back(storage->gi_probe_get_octree_buffer(probe));
+ u.ids.push_back(storage->voxel_gi_get_octree_buffer(probe));
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 2;
- u.ids.push_back(storage->gi_probe_get_data_buffer(probe));
+ u.ids.push_back(storage->voxel_gi_get_data_buffer(probe));
uniforms.push_back(u);
}
@@ -2100,7 +2100,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 9;
- u.ids.push_back(storage->gi_probe_get_sdf_texture(probe));
+ u.ids.push_back(storage->voxel_gi_get_sdf_texture(probe));
uniforms.push_back(u);
}
{
@@ -2118,11 +2118,11 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 3;
- u.ids.push_back(gi->gi_probe_lights_uniform);
+ u.ids.push_back(gi->voxel_gi_lights_uniform);
copy_uniforms.push_back(u);
}
- mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT], 0);
+ mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_COMPUTE_LIGHT], 0);
copy_uniforms = uniforms; //restore
@@ -2133,9 +2133,9 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
u.ids.push_back(texture);
copy_uniforms.push_back(u);
}
- mipmap.second_bounce_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE], 0);
+ mipmap.second_bounce_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_COMPUTE_SECOND_BOUNCE], 0);
} else {
- mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP], 0);
+ mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_COMPUTE_MIPMAP], 0);
}
}
@@ -2147,7 +2147,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
uniforms.push_back(u);
}
- mipmap.write_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE], 0);
+ mipmap.write_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_WRITE_TEXTURE], 0);
mipmaps.push_back(mipmap);
}
@@ -2158,7 +2158,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
int mipmap_index = 0;
while (mipmap_index < mipmaps.size()) {
- GIProbeInstance::DynamicMap dmap;
+ VoxelGIInstance::DynamicMap dmap;
if (oversample > 0) {
dmap.size = dynamic_map_size * (1 << oversample);
@@ -2217,7 +2217,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 3;
- u.ids.push_back(gi->gi_probe_lights_uniform);
+ u.ids.push_back(gi->voxel_gi_lights_uniform);
uniforms.push_back(u);
}
@@ -2253,7 +2253,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 9;
- u.ids.push_back(storage->gi_probe_get_sdf_texture(probe));
+ u.ids.push_back(storage->voxel_gi_get_sdf_texture(probe));
uniforms.push_back(u);
}
{
@@ -2278,7 +2278,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
uniforms.push_back(u);
}
- dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0);
+ dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0);
}
} else {
bool plot = dmap.mipmap >= 0;
@@ -2322,7 +2322,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 9;
- u.ids.push_back(storage->gi_probe_get_sdf_texture(probe));
+ u.ids.push_back(storage->voxel_gi_get_sdf_texture(probe));
uniforms.push_back(u);
}
{
@@ -2345,7 +2345,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
dmap.uniform_set = RD::get_singleton()->uniform_set_create(
uniforms,
- gi->giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : (write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT)],
+ gi->voxel_gi_lighting_shader_version_shaders[(write && plot) ? VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : (write ? VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_PLOT)],
0);
}
@@ -2370,15 +2370,15 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
uint32_t light_count = 0;
if (p_update_light_instances || p_dynamic_objects.size() > 0) {
- light_count = MIN(gi->gi_probe_max_lights, (uint32_t)p_light_instances.size());
+ light_count = MIN(gi->voxel_gi_max_lights, (uint32_t)p_light_instances.size());
{
- Transform to_cell = storage->gi_probe_get_to_cell_xform(probe);
- Transform to_probe_xform = (transform * to_cell.affine_inverse()).affine_inverse();
+ Transform3D to_cell = storage->voxel_gi_get_to_cell_xform(probe);
+ Transform3D to_probe_xform = (transform * to_cell.affine_inverse()).affine_inverse();
//update lights
for (uint32_t i = 0; i < light_count; i++) {
- GIProbeLight &l = gi->gi_probe_lights[i];
+ VoxelGILight &l = gi->voxel_gi_lights[i];
RID light_instance = p_light_instances[i];
RID light = p_scene_render->light_instance_get_base_light(light_instance);
@@ -2399,7 +2399,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
l.cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
l.inv_spot_attenuation = 1.0f / storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
- Transform xform = p_scene_render->light_instance_get_base_transform(light_instance);
+ Transform3D xform = p_scene_render->light_instance_get_base_transform(light_instance);
Vector3 pos = to_probe_xform.xform(xform.origin);
Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_axis(2)).normalized();
@@ -2415,7 +2415,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
l.has_shadow = storage->light_has_shadow(light);
}
- RD::get_singleton()->buffer_update(gi->gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi->gi_probe_lights);
+ RD::get_singleton()->buffer_update(gi->voxel_gi_lights_uniform, 0, sizeof(VoxelGILight) * light_count, gi->voxel_gi_lights);
}
}
@@ -2424,17 +2424,17 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
if (mipmaps.size()) {
//can update mipmaps
- Vector3i probe_size = storage->gi_probe_get_octree_size(probe);
+ Vector3i probe_size = storage->voxel_gi_get_octree_size(probe);
- GIProbePushConstant push_constant;
+ VoxelGIPushConstant push_constant;
push_constant.limits[0] = probe_size.x;
push_constant.limits[1] = probe_size.y;
push_constant.limits[2] = probe_size.z;
push_constant.stack_size = mipmaps.size();
push_constant.emission_scale = 1.0;
- push_constant.propagation = storage->gi_probe_get_propagation(probe);
- push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe);
+ push_constant.propagation = storage->voxel_gi_get_propagation(probe);
+ push_constant.dynamic_range = storage->voxel_gi_get_dynamic_range(probe);
push_constant.light_count = light_count;
push_constant.aniso_strength = 0;
@@ -2446,7 +2446,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
int passes;
if (p_update_light_instances) {
- passes = storage->gi_probe_is_using_two_bounces(probe) ? 2 : 1;
+ passes = storage->voxel_gi_is_using_two_bounces(probe) ? 2 : 1;
} else {
passes = 1; //only re-blitting is necessary
}
@@ -2457,9 +2457,9 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
if (p_update_light_instances) {
for (int i = 0; i < mipmaps.size(); i++) {
if (i == 0) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[pass == 0 ? VOXEL_GI_SHADER_VERSION_COMPUTE_LIGHT : VOXEL_GI_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]);
} else if (i == 1) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_COMPUTE_MIPMAP]);
}
if (pass == 1 || i > 0) {
@@ -2477,7 +2477,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
int wg_todo = (mipmaps[i].cell_count - 1) / wg_size + 1;
while (wg_todo) {
int wg_count = MIN(wg_todo, wg_limit_x);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIPushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
wg_todo -= wg_count;
push_constant.cell_offset += wg_count * wg_size;
@@ -2487,7 +2487,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
}
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_WRITE_TEXTURE]);
for (int i = 0; i < mipmaps.size(); i++) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mipmaps[i].write_uniform_set, 0);
@@ -2498,7 +2498,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
int wg_todo = (mipmaps[i].cell_count - 1) / wg_size + 1;
while (wg_todo) {
int wg_count = MIN(wg_todo, wg_limit_x);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIPushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
wg_todo -= wg_count;
push_constant.cell_offset += wg_count * wg_size;
@@ -2513,15 +2513,15 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
has_dynamic_object_data = false; //clear until dynamic object data is used again
if (p_dynamic_objects.size() && dynamic_maps.size()) {
- Vector3i octree_size = storage->gi_probe_get_octree_size(probe);
+ Vector3i octree_size = storage->voxel_gi_get_octree_size(probe);
int multiplier = dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
- Transform oversample_scale;
+ Transform3D oversample_scale;
oversample_scale.basis.scale(Vector3(multiplier, multiplier, multiplier));
- Transform to_cell = oversample_scale * storage->gi_probe_get_to_cell_xform(probe);
- Transform to_world_xform = transform * to_cell.affine_inverse();
- Transform to_probe_xform = to_world_xform.affine_inverse();
+ Transform3D to_cell = oversample_scale * storage->voxel_gi_get_to_cell_xform(probe);
+ Transform3D to_world_xform = transform * to_cell.affine_inverse();
+ Transform3D to_probe_xform = to_world_xform.affine_inverse();
AABB probe_aabb(Vector3(), octree_size);
@@ -2529,7 +2529,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
for (int i = 0; i < (int)p_dynamic_objects.size(); i++) {
RendererSceneRender::GeometryInstance *instance = p_dynamic_objects[i];
- //transform aabb to giprobe
+ //transform aabb to voxel_gi
AABB aabb = (to_probe_xform * p_scene_render->geometry_instance_get_transform(instance)).xform(p_scene_render->geometry_instance_get_aabb(instance));
//this needs to wrap to grid resolution to avoid jitter
@@ -2575,8 +2575,8 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
Vector3 render_dir = render_z[j];
Vector3 up_dir = render_up[j];
- Vector3 center = aabb.position + aabb.size * 0.5;
- Transform xform;
+ Vector3 center = aabb.get_center();
+ Transform3D xform;
xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir);
Vector3 x_dir = xform.basis.get_axis(0).abs();
@@ -2601,8 +2601,8 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
p_scene_render->_render_material(to_world_xform * xform, cm, true, p_scene_render->cull_argument, dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size));
- GIProbeDynamicPushConstant push_constant;
- memset(&push_constant, 0, sizeof(GIProbeDynamicPushConstant));
+ VoxelGIDynamicPushConstant push_constant;
+ memset(&push_constant, 0, sizeof(VoxelGIDynamicPushConstant));
push_constant.limits[0] = octree_size.x;
push_constant.limits[1] = octree_size.y;
push_constant.limits[2] = octree_size.z;
@@ -2619,7 +2619,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
push_constant.z_base = xform.origin[z_axis];
push_constant.z_sign = (z_flip ? -1.0 : 1.0);
push_constant.pos_multiplier = float(1.0) / multiplier;
- push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe);
+ push_constant.dynamic_range = storage->voxel_gi_get_dynamic_range(probe);
push_constant.flip_x = x_flip;
push_constant.flip_y = y_flip;
push_constant.rect_pos[0] = rect.position[0];
@@ -2631,16 +2631,16 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
push_constant.prev_rect_size[0] = 0;
push_constant.prev_rect_size[1] = 0;
push_constant.on_mipmap = false;
- push_constant.propagation = storage->gi_probe_get_propagation(probe);
+ push_constant.propagation = storage->voxel_gi_get_propagation(probe);
push_constant.pad[0] = 0;
push_constant.pad[1] = 0;
push_constant.pad[2] = 0;
//process lighting
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[0].uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIDynamicPushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
//print_line("rect: " + itos(i) + ": " + rect);
@@ -2695,14 +2695,14 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::get_singleton()->compute_list_add_barrier(compute_list);
if (dynamic_maps[k].mipmap < 0) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]);
} else if (k < dynamic_maps.size() - 1) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]);
} else {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]);
}
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[k].uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIDynamicPushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
}
@@ -2713,22 +2713,22 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
has_dynamic_object_data = true; //clear until dynamic object data is used again
}
- last_probe_version = storage->gi_probe_get_version(probe);
+ last_probe_version = storage->voxel_gi_get_version(probe);
}
-void RendererSceneGIRD::GIProbeInstance::debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
+void RendererSceneGIRD::VoxelGIInstance::debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
if (mipmaps.size() == 0) {
return;
}
- CameraMatrix cam_transform = (p_camera_with_transform * CameraMatrix(transform)) * CameraMatrix(storage->gi_probe_get_to_cell_xform(probe).affine_inverse());
+ CameraMatrix cam_transform = (p_camera_with_transform * CameraMatrix(transform)) * CameraMatrix(storage->voxel_gi_get_to_cell_xform(probe).affine_inverse());
int level = 0;
- Vector3i octree_size = storage->gi_probe_get_octree_size(probe);
+ Vector3i octree_size = storage->voxel_gi_get_octree_size(probe);
- GIProbeDebugPushConstant push_constant;
+ VoxelGIDebugPushConstant push_constant;
push_constant.alpha = p_alpha;
- push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe);
+ push_constant.dynamic_range = storage->voxel_gi_get_dynamic_range(probe);
push_constant.cell_offset = mipmaps[level].cell_offset;
push_constant.level = level;
@@ -2743,15 +2743,15 @@ void RendererSceneGIRD::GIProbeInstance::debug(RD::DrawListID p_draw_list, RID p
}
}
- if (gi->giprobe_debug_uniform_set.is_valid()) {
- RD::get_singleton()->free(gi->giprobe_debug_uniform_set);
+ if (gi->voxel_gi_debug_uniform_set.is_valid()) {
+ RD::get_singleton()->free(gi->voxel_gi_debug_uniform_set);
}
Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 1;
- u.ids.push_back(storage->gi_probe_get_data_buffer(probe));
+ u.ids.push_back(storage->voxel_gi_get_data_buffer(probe));
uniforms.push_back(u);
}
{
@@ -2776,19 +2776,19 @@ void RendererSceneGIRD::GIProbeInstance::debug(RD::DrawListID p_draw_list, RID p
cell_count = mipmaps[level].cell_count;
}
- gi->giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_debug_shader_version_shaders[0], 0);
+ gi->voxel_gi_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->voxel_gi_debug_shader_version_shaders[0], 0);
- int giprobe_debug_pipeline = GI_PROBE_DEBUG_COLOR;
+ int voxel_gi_debug_pipeline = VOXEL_GI_DEBUG_COLOR;
if (p_emission) {
- giprobe_debug_pipeline = GI_PROBE_DEBUG_EMISSION;
+ voxel_gi_debug_pipeline = VOXEL_GI_DEBUG_EMISSION;
} else if (p_lighting) {
- giprobe_debug_pipeline = has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT;
+ voxel_gi_debug_pipeline = has_dynamic_object_data ? VOXEL_GI_DEBUG_LIGHT_FULL : VOXEL_GI_DEBUG_LIGHT;
}
RD::get_singleton()->draw_list_bind_render_pipeline(
p_draw_list,
- gi->giprobe_debug_shader_version_pipelines[giprobe_debug_pipeline].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, gi->giprobe_debug_uniform_set, 0);
- RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant));
+ gi->voxel_gi_debug_shader_version_pipelines[voxel_gi_debug_pipeline].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, gi->voxel_gi_debug_uniform_set, 0);
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(VoxelGIDebugPushConstant));
RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36);
}
@@ -2812,13 +2812,11 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
{
//kinda complicated to compute the amount of slots, we try to use as many as we can
- gi_probe_max_lights = 32;
+ voxel_gi_lights = memnew_arr(VoxelGILight, voxel_gi_max_lights);
+ voxel_gi_lights_uniform = RD::get_singleton()->uniform_buffer_create(voxel_gi_max_lights * sizeof(VoxelGILight));
+ voxel_gi_quality = RS::VoxelGIQuality(CLAMP(int(GLOBAL_GET("rendering/global_illumination/voxel_gi/quality")), 0, 1));
- gi_probe_lights = memnew_arr(GIProbeLight, gi_probe_max_lights);
- gi_probe_lights_uniform = RD::get_singleton()->uniform_buffer_create(gi_probe_max_lights * sizeof(GIProbeLight));
- gi_probe_quality = RS::GIProbeQuality(CLAMP(int(GLOBAL_GET("rendering/global_illumination/gi_probes/quality")), 0, 1));
-
- String defines = "\n#define MAX_LIGHTS " + itos(gi_probe_max_lights) + "\n";
+ String defines = "\n#define MAX_LIGHTS " + itos(voxel_gi_max_lights) + "\n";
Vector<String> versions;
versions.push_back("\n#define MODE_COMPUTE_LIGHT\n");
@@ -2830,11 +2828,11 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n");
versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
- giprobe_shader.initialize(versions, defines);
- giprobe_lighting_shader_version = giprobe_shader.version_create();
- for (int i = 0; i < GI_PROBE_SHADER_VERSION_MAX; i++) {
- giprobe_lighting_shader_version_shaders[i] = giprobe_shader.version_get_shader(giprobe_lighting_shader_version, i);
- giprobe_lighting_shader_version_pipelines[i] = RD::get_singleton()->compute_pipeline_create(giprobe_lighting_shader_version_shaders[i]);
+ voxel_gi_shader.initialize(versions, defines);
+ voxel_gi_lighting_shader_version = voxel_gi_shader.version_create();
+ for (int i = 0; i < VOXEL_GI_SHADER_VERSION_MAX; i++) {
+ voxel_gi_lighting_shader_version_shaders[i] = voxel_gi_shader.version_get_shader(voxel_gi_lighting_shader_version, i);
+ voxel_gi_lighting_shader_version_pipelines[i] = RD::get_singleton()->compute_pipeline_create(voxel_gi_lighting_shader_version_shaders[i]);
}
}
@@ -2846,10 +2844,10 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
versions.push_back("\n#define MODE_DEBUG_EMISSION\n");
versions.push_back("\n#define MODE_DEBUG_LIGHT\n#define MODE_DEBUG_LIGHT_FULL\n");
- giprobe_debug_shader.initialize(versions, defines);
- giprobe_debug_shader_version = giprobe_debug_shader.version_create();
- for (int i = 0; i < GI_PROBE_DEBUG_MAX; i++) {
- giprobe_debug_shader_version_shaders[i] = giprobe_debug_shader.version_get_shader(giprobe_debug_shader_version, i);
+ voxel_gi_debug_shader.initialize(versions, defines);
+ voxel_gi_debug_shader_version = voxel_gi_debug_shader.version_create();
+ for (int i = 0; i < VOXEL_GI_DEBUG_MAX; i++) {
+ voxel_gi_debug_shader_version_shaders[i] = voxel_gi_debug_shader.version_get_shader(voxel_gi_debug_shader_version, i);
RD::PipelineRasterizationState rs;
rs.cull_mode = RD::POLYGON_CULL_FRONT;
@@ -2858,7 +2856,7 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
ds.enable_depth_write = true;
ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
- giprobe_debug_shader_version_pipelines[i].setup(giprobe_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
+ voxel_gi_debug_shader_version_pipelines[i].setup(voxel_gi_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
}
}
@@ -2944,12 +2942,12 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
//calculate tables
String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
Vector<String> gi_modes;
- gi_modes.push_back("\n#define USE_GIPROBES\n");
+ gi_modes.push_back("\n#define USE_VOXEL_GI_INSTANCES\n");
gi_modes.push_back("\n#define USE_SDFGI\n");
- gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_GIPROBES\n");
- gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_GIPROBES\n");
+ gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_VOXEL_GI_INSTANCES\n");
+ gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_VOXEL_GI_INSTANCES\n");
gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n");
- gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_GIPROBES\n");
+ gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_VOXEL_GI_INSTANCES\n");
shader.initialize(gi_modes, defines);
shader_version = shader.version_create();
@@ -2991,17 +2989,17 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
}
}
}
- default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GIProbeData) * MAX_GIPROBES);
+ default_voxel_gi_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(VoxelGIData) * MAX_VOXEL_GI_INSTANCES);
half_resolution = GLOBAL_GET("rendering/global_illumination/gi/use_half_resolution");
}
void RendererSceneGIRD::free() {
- RD::get_singleton()->free(default_giprobe_buffer);
- RD::get_singleton()->free(gi_probe_lights_uniform);
+ RD::get_singleton()->free(default_voxel_gi_buffer);
+ RD::get_singleton()->free(voxel_gi_lights_uniform);
RD::get_singleton()->free(sdfgi_ubo);
- giprobe_debug_shader.version_free(giprobe_debug_shader_version);
- giprobe_shader.version_free(giprobe_lighting_shader_version);
+ voxel_gi_debug_shader.version_free(voxel_gi_debug_shader_version);
+ voxel_gi_shader.version_free(voxel_gi_lighting_shader_version);
shader.version_free(shader_version);
sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader);
sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader);
@@ -3009,7 +3007,9 @@ void RendererSceneGIRD::free() {
sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader);
sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader);
- memdelete_arr(gi_probe_lights);
+ if (voxel_gi_lights) {
+ memdelete_arr(voxel_gi_lights);
+ }
}
RendererSceneGIRD::SDFGI *RendererSceneGIRD::create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size) {
@@ -3020,36 +3020,34 @@ RendererSceneGIRD::SDFGI *RendererSceneGIRD::create_sdfgi(RendererSceneEnvironme
return sdfgi;
}
-void RendererSceneGIRD::setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used, RendererSceneRenderRD *p_scene_render) {
- r_gi_probes_used = 0;
+void RendererSceneGIRD::setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render) {
+ r_voxel_gi_instances_used = 0;
// feels a little dirty to use our container this way but....
- RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers);
+ RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND(rb == nullptr);
- RID gi_probe_buffer = p_scene_render->render_buffers_get_gi_probe_buffer(p_render_buffers);
-
- RD::get_singleton()->draw_command_begin_label("GIProbes Setup");
+ RID voxel_gi_buffer = p_scene_render->render_buffers_get_voxel_gi_buffer(p_render_buffers);
- GIProbeData gi_probe_data[MAX_GIPROBES];
+ VoxelGIData voxel_gi_data[MAX_VOXEL_GI_INSTANCES];
- bool giprobes_changed = false;
+ bool voxel_gi_instances_changed = false;
- Transform to_camera;
+ Transform3D to_camera;
to_camera.origin = p_transform.origin; //only translation, make local
- for (int i = 0; i < MAX_GIPROBES; i++) {
+ for (int i = 0; i < MAX_VOXEL_GI_INSTANCES; i++) {
RID texture;
- if (i < (int)p_gi_probes.size()) {
- GIProbeInstance *gipi = get_probe_instance(p_gi_probes[i]);
+ if (i < (int)p_voxel_gi_instances.size()) {
+ VoxelGIInstance *gipi = get_probe_instance(p_voxel_gi_instances[i]);
if (gipi) {
texture = gipi->texture;
- GIProbeData &gipd = gi_probe_data[i];
+ VoxelGIData &gipd = voxel_gi_data[i];
RID base_probe = gipi->probe;
- Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera;
+ Transform3D to_cell = storage->voxel_gi_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera;
gipd.xform[0] = to_cell.basis.elements[0][0];
gipd.xform[1] = to_cell.basis.elements[1][0];
@@ -3068,63 +3066,63 @@ void RendererSceneGIRD::setup_giprobes(RID p_render_buffers, const Transform &p_
gipd.xform[14] = to_cell.origin.z;
gipd.xform[15] = 1;
- Vector3 bounds = storage->gi_probe_get_octree_size(base_probe);
+ Vector3 bounds = storage->voxel_gi_get_octree_size(base_probe);
gipd.bounds[0] = bounds.x;
gipd.bounds[1] = bounds.y;
gipd.bounds[2] = bounds.z;
- gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe);
- gipd.bias = storage->gi_probe_get_bias(base_probe);
- gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe);
- gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe);
- gipd.anisotropy_strength = 0;
- gipd.ao = storage->gi_probe_get_ao(base_probe);
- gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f);
+ gipd.dynamic_range = storage->voxel_gi_get_dynamic_range(base_probe) * storage->voxel_gi_get_energy(base_probe);
+ gipd.bias = storage->voxel_gi_get_bias(base_probe);
+ gipd.normal_bias = storage->voxel_gi_get_normal_bias(base_probe);
+ gipd.blend_ambient = !storage->voxel_gi_is_interior(base_probe);
gipd.mipmaps = gipi->mipmaps.size();
}
- r_gi_probes_used++;
+ r_voxel_gi_instances_used++;
}
if (texture == RID()) {
texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
}
- if (texture != rb->gi.giprobe_textures[i]) {
- giprobes_changed = true;
- rb->gi.giprobe_textures[i] = texture;
+ if (texture != rb->gi.voxel_gi_textures[i]) {
+ voxel_gi_instances_changed = true;
+ rb->gi.voxel_gi_textures[i] = texture;
}
}
- if (giprobes_changed) {
+ if (voxel_gi_instances_changed) {
if (RD::get_singleton()->uniform_set_is_valid(rb->gi.uniform_set)) {
RD::get_singleton()->free(rb->gi.uniform_set);
}
rb->gi.uniform_set = RID();
if (rb->volumetric_fog) {
- if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
- RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
- RD::get_singleton()->free(rb->volumetric_fog->uniform_set2);
+ if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->fog_uniform_set)) {
+ RD::get_singleton()->free(rb->volumetric_fog->fog_uniform_set);
+ RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set);
+ RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set2);
}
- rb->volumetric_fog->uniform_set = RID();
- rb->volumetric_fog->uniform_set2 = RID();
+ rb->volumetric_fog->fog_uniform_set = RID();
+ rb->volumetric_fog->process_uniform_set = RID();
+ rb->volumetric_fog->process_uniform_set2 = RID();
}
}
- if (p_gi_probes.size() > 0) {
- RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GIProbeData) * MIN((uint64_t)MAX_GIPROBES, p_gi_probes.size()), gi_probe_data, RD::BARRIER_MASK_COMPUTE);
- }
+ if (p_voxel_gi_instances.size() > 0) {
+ RD::get_singleton()->draw_command_begin_label("VoxelGIs Setup");
- RD::get_singleton()->draw_command_end_label();
+ RD::get_singleton()->buffer_update(voxel_gi_buffer, 0, sizeof(VoxelGIData) * MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size()), voxel_gi_data, RD::BARRIER_MASK_COMPUTE);
+
+ RD::get_singleton()->draw_command_end_label();
+ }
}
-void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, RendererSceneRenderRD *p_scene_render) {
+void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render) {
RD::get_singleton()->draw_command_begin_label("GI Render");
- RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers);
+ RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND(rb == nullptr);
- RendererSceneEnvironmentRD *env = p_scene_render->environment_owner.getornull(p_environment);
if (rb->ambient_buffer.is_null() || rb->gi.using_half_size_gi != half_resolution) {
if (rb->ambient_buffer.is_valid()) {
@@ -3134,8 +3132,8 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.width = rb->width;
- tf.height = rb->height;
+ tf.width = rb->internal_width;
+ tf.height = rb->internal_height;
if (half_resolution) {
tf.width >>= 1;
tf.height >>= 1;
@@ -3148,30 +3146,20 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
PushConstant push_constant;
- push_constant.screen_size[0] = rb->width;
- push_constant.screen_size[1] = rb->height;
+ push_constant.screen_size[0] = rb->internal_width;
+ push_constant.screen_size[1] = rb->internal_height;
push_constant.z_near = p_projection.get_z_near();
push_constant.z_far = p_projection.get_z_far();
push_constant.orthogonal = p_projection.is_orthogonal();
- push_constant.proj_info[0] = -2.0f / (rb->width * p_projection.matrix[0][0]);
- push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]);
+ push_constant.proj_info[0] = -2.0f / (rb->internal_width * p_projection.matrix[0][0]);
+ push_constant.proj_info[1] = -2.0f / (rb->internal_height * p_projection.matrix[1][1]);
push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0];
push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1];
- push_constant.max_giprobes = MIN((uint64_t)MAX_GIPROBES, p_gi_probes.size());
- push_constant.high_quality_vct = gi_probe_quality == RS::GI_PROBE_QUALITY_HIGH;
+ push_constant.max_voxel_gi_instances = MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size());
+ push_constant.high_quality_vct = voxel_gi_quality == RS::VOXEL_GI_QUALITY_HIGH;
bool use_sdfgi = rb->sdfgi != nullptr;
- bool use_giprobes = push_constant.max_giprobes > 0;
-
- if (env) {
- push_constant.ao_color[0] = env->ao_color.r;
- push_constant.ao_color[1] = env->ao_color.g;
- push_constant.ao_color[2] = env->ao_color.b;
- } else {
- push_constant.ao_color[0] = 0;
- push_constant.ao_color[1] = 0;
- push_constant.ao_color[2] = 0;
- }
+ bool use_voxel_gi_instances = push_constant.max_voxel_gi_instances > 0;
push_constant.cam_rotation[0] = p_transform.basis[0][0];
push_constant.cam_rotation[1] = p_transform.basis[1][0];
@@ -3311,7 +3299,7 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 14;
- RID buffer = p_gi_probe_buffer.is_valid() ? p_gi_probe_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
+ RID buffer = p_voxel_gi_buffer.is_valid() ? p_voxel_gi_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
u.ids.push_back(buffer);
uniforms.push_back(u);
}
@@ -3326,15 +3314,15 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 16;
- u.ids.push_back(rb->gi.giprobe_buffer);
+ u.ids.push_back(rb->gi.voxel_gi_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 17;
- for (int i = 0; i < MAX_GIPROBES; i++) {
- u.ids.push_back(rb->gi.giprobe_textures[i]);
+ for (int i = 0; i < MAX_VOXEL_GI_INSTANCES; i++) {
+ u.ids.push_back(rb->gi.voxel_gi_textures[i]);
}
uniforms.push_back(u);
}
@@ -3345,58 +3333,59 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
Mode mode;
if (rb->gi.using_half_size_gi) {
- mode = (use_sdfgi && use_giprobes) ? MODE_HALF_RES_COMBINED : (use_sdfgi ? MODE_HALF_RES_SDFGI : MODE_HALF_RES_GIPROBE);
+ mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_HALF_RES_COMBINED : (use_sdfgi ? MODE_HALF_RES_SDFGI : MODE_HALF_RES_VOXEL_GI);
} else {
- mode = (use_sdfgi && use_giprobes) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_GIPROBE);
+ mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_VOXEL_GI);
}
+
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[mode]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->gi.uniform_set, 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
if (rb->gi.using_half_size_gi) {
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width >> 1, rb->height >> 1, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->internal_width >> 1, rb->internal_height >> 1, 1);
} else {
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->internal_width, rb->internal_height, 1);
}
//do barrier later to allow oeverlap
//RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //no barriers, let other compute, raster and transfer happen at the same time
RD::get_singleton()->draw_command_end_label();
}
-RID RendererSceneGIRD::gi_probe_instance_create(RID p_base) {
- GIProbeInstance gi_probe;
- gi_probe.gi = this;
- gi_probe.storage = storage;
- gi_probe.probe = p_base;
- RID rid = gi_probe_instance_owner.make_rid(gi_probe);
+RID RendererSceneGIRD::voxel_gi_instance_create(RID p_base) {
+ VoxelGIInstance voxel_gi;
+ voxel_gi.gi = this;
+ voxel_gi.storage = storage;
+ voxel_gi.probe = p_base;
+ RID rid = voxel_gi_instance_owner.make_rid(voxel_gi);
return rid;
}
-void RendererSceneGIRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {
- GIProbeInstance *gi_probe = get_probe_instance(p_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererSceneGIRD::voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) {
+ VoxelGIInstance *voxel_gi = get_probe_instance(p_probe);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->transform = p_xform;
+ voxel_gi->transform = p_xform;
}
-bool RendererSceneGIRD::gi_probe_needs_update(RID p_probe) const {
- GIProbeInstance *gi_probe = get_probe_instance(p_probe);
- ERR_FAIL_COND_V(!gi_probe, false);
+bool RendererSceneGIRD::voxel_gi_needs_update(RID p_probe) const {
+ VoxelGIInstance *voxel_gi = get_probe_instance(p_probe);
+ ERR_FAIL_COND_V(!voxel_gi, false);
- return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe);
+ return voxel_gi->last_probe_version != storage->voxel_gi_get_version(voxel_gi->probe);
}
-void RendererSceneGIRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
- GIProbeInstance *gi_probe = get_probe_instance(p_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererSceneGIRD::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
+ VoxelGIInstance *voxel_gi = get_probe_instance(p_probe);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->update(p_update_light_instances, p_light_instances, p_dynamic_objects, p_scene_render);
+ voxel_gi->update(p_update_light_instances, p_light_instances, p_dynamic_objects, p_scene_render);
}
-void RendererSceneGIRD::debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererSceneGIRD::debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
+ VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->debug(p_draw_list, p_framebuffer, p_camera_with_transform, p_lighting, p_emission, p_alpha);
+ voxel_gi->debug(p_draw_list, p_framebuffer, p_camera_with_transform, p_lighting, p_emission, p_alpha);
}
diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
index 59f5f374d1..9f6fc8a9b7 100644
--- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
@@ -38,13 +38,13 @@
#include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h"
#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
#include "servers/rendering/renderer_rd/shaders/gi.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/giprobe.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/giprobe_debug.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/voxel_gi.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
@@ -56,9 +56,9 @@ class RendererSceneGIRD {
private:
RendererStorageRD *storage;
- /* GIPROBE INSTANCE */
+ /* VOXEL_GI INSTANCE */
- struct GIProbeLight {
+ struct VoxelGILight {
uint32_t type;
float energy;
float radius;
@@ -74,7 +74,7 @@ private:
uint32_t has_shadow;
};
- struct GIProbePushConstant {
+ struct VoxelGIPushConstant {
int32_t limits[3];
uint32_t stack_size;
@@ -89,7 +89,7 @@ private:
uint32_t pad;
};
- struct GIProbeDynamicPushConstant {
+ struct VoxelGIDynamicPushConstant {
int32_t limits[3];
uint32_t light_count;
int32_t x_dir[3];
@@ -110,36 +110,36 @@ private:
float pad[3];
};
- GIProbeLight *gi_probe_lights;
- uint32_t gi_probe_max_lights;
- RID gi_probe_lights_uniform;
+ VoxelGILight *voxel_gi_lights = nullptr;
+ uint32_t voxel_gi_max_lights = 32;
+ RID voxel_gi_lights_uniform;
enum {
- GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT,
- GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE,
- GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP,
- GI_PROBE_SHADER_VERSION_WRITE_TEXTURE,
- GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING,
- GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE,
- GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT,
- GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT,
- GI_PROBE_SHADER_VERSION_MAX
+ VOXEL_GI_SHADER_VERSION_COMPUTE_LIGHT,
+ VOXEL_GI_SHADER_VERSION_COMPUTE_SECOND_BOUNCE,
+ VOXEL_GI_SHADER_VERSION_COMPUTE_MIPMAP,
+ VOXEL_GI_SHADER_VERSION_WRITE_TEXTURE,
+ VOXEL_GI_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING,
+ VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE,
+ VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_PLOT,
+ VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT,
+ VOXEL_GI_SHADER_VERSION_MAX
};
- GiprobeShaderRD giprobe_shader;
- RID giprobe_lighting_shader_version;
- RID giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_MAX];
- RID giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_MAX];
+ VoxelGiShaderRD voxel_gi_shader;
+ RID voxel_gi_lighting_shader_version;
+ RID voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_MAX];
+ RID voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_MAX];
enum {
- GI_PROBE_DEBUG_COLOR,
- GI_PROBE_DEBUG_LIGHT,
- GI_PROBE_DEBUG_EMISSION,
- GI_PROBE_DEBUG_LIGHT_FULL,
- GI_PROBE_DEBUG_MAX
+ VOXEL_GI_DEBUG_COLOR,
+ VOXEL_GI_DEBUG_LIGHT,
+ VOXEL_GI_DEBUG_EMISSION,
+ VOXEL_GI_DEBUG_LIGHT_FULL,
+ VOXEL_GI_DEBUG_MAX
};
- struct GIProbeDebugPushConstant {
+ struct VoxelGIDebugPushConstant {
float projection[16];
uint32_t cell_offset;
float dynamic_range;
@@ -149,11 +149,11 @@ private:
uint32_t pad;
};
- GiprobeDebugShaderRD giprobe_debug_shader;
- RID giprobe_debug_shader_version;
- RID giprobe_debug_shader_version_shaders[GI_PROBE_DEBUG_MAX];
- PipelineCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX];
- RID giprobe_debug_uniform_set;
+ VoxelGiDebugShaderRD voxel_gi_debug_shader;
+ RID voxel_gi_debug_shader_version;
+ RID voxel_gi_debug_shader_version_shaders[VOXEL_GI_DEBUG_MAX];
+ PipelineCacheRD voxel_gi_debug_shader_version_pipelines[VOXEL_GI_DEBUG_MAX];
+ RID voxel_gi_debug_uniform_set;
/* SDFGI */
@@ -326,11 +326,11 @@ private:
} sdfgi_shader;
public:
- /* GIPROBE INSTANCE */
+ /* VOXEL_GI INSTANCE */
- //@TODO GIProbeInstance is still directly used in the render code, we'll address this when we refactor the render code itself.
+ //@TODO VoxelGIInstance is still directly used in the render code, we'll address this when we refactor the render code itself.
- struct GIProbeInstance {
+ struct VoxelGIInstance {
// access to our containers
RendererStorageRD *storage;
RendererSceneGIRD *gi;
@@ -374,25 +374,25 @@ public:
bool has_dynamic_object_data = false;
- Transform transform;
+ Transform3D transform;
void update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
void debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
};
- mutable RID_Owner<GIProbeInstance> gi_probe_instance_owner;
+ mutable RID_Owner<VoxelGIInstance> voxel_gi_instance_owner;
- _FORCE_INLINE_ GIProbeInstance *get_probe_instance(RID p_probe) const {
- return gi_probe_instance_owner.getornull(p_probe);
+ _FORCE_INLINE_ VoxelGIInstance *get_probe_instance(RID p_probe) const {
+ return voxel_gi_instance_owner.get_or_null(p_probe);
};
- _FORCE_INLINE_ RID gi_probe_instance_get_texture(RID p_probe) {
- GIProbeInstance *gi_probe = get_probe_instance(p_probe);
- ERR_FAIL_COND_V(!gi_probe, RID());
- return gi_probe->texture;
+ _FORCE_INLINE_ RID voxel_gi_instance_get_texture(RID p_probe) {
+ VoxelGIInstance *voxel_gi = get_probe_instance(p_probe);
+ ERR_FAIL_COND_V(!voxel_gi, RID());
+ return voxel_gi->texture;
};
- RS::GIProbeQuality gi_probe_quality = RS::GI_PROBE_QUALITY_HIGH;
+ RS::VoxelGIQuality voxel_gi_quality = RS::VOXEL_GI_QUALITY_HIGH;
/* SDFGI */
@@ -527,10 +527,10 @@ public:
int get_pending_region_data(int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const;
void update_cascades();
- void debug_draw(const CameraMatrix &p_projection, const Transform &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture);
+ void debug_draw(const CameraMatrix &p_projection, const Transform3D &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture);
void debug_probes(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform);
- void pre_process_gi(const Transform &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render);
+ void pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render);
void render_region(RID p_render_buffers, int p_region, const PagedArray<RendererSceneRender::GeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render);
void render_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render);
};
@@ -551,13 +551,13 @@ public:
/* GI */
enum {
- MAX_GIPROBES = 8
+ MAX_VOXEL_GI_INSTANCES = 8
};
// Struct for use in render buffer
struct RenderBuffersGI {
- RID giprobe_textures[MAX_GIPROBES];
- RID giprobe_buffer;
+ RID voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
+ RID voxel_gi_buffer;
RID full_buffer;
RID full_dispatch;
@@ -601,7 +601,7 @@ public:
ProbeCascadeData cascades[SDFGI::MAX_CASCADES];
};
- struct GIProbeData {
+ struct VoxelGIData {
float xform[16];
float bounds[3];
float dynamic_range;
@@ -611,9 +611,9 @@ public:
uint32_t blend_ambient;
uint32_t texture_slot;
- float anisotropy_strength;
- float ao;
- float ao_size;
+ uint32_t pad0;
+ uint32_t pad1;
+ uint32_t pad2;
uint32_t mipmaps;
};
@@ -623,28 +623,27 @@ public:
float z_far;
float proj_info[4];
- float ao_color[3];
- uint32_t max_giprobes;
+ uint32_t max_voxel_gi_instances;
uint32_t high_quality_vct;
uint32_t orthogonal;
- uint32_t pad[2];
+ uint32_t pad;
float cam_rotation[12];
};
RID sdfgi_ubo;
enum Mode {
- MODE_GIPROBE,
+ MODE_VOXEL_GI,
MODE_SDFGI,
MODE_COMBINED,
- MODE_HALF_RES_GIPROBE,
+ MODE_HALF_RES_VOXEL_GI,
MODE_HALF_RES_SDFGI,
MODE_HALF_RES_COMBINED,
MODE_MAX
};
- RID default_giprobe_buffer;
+ RID default_voxel_gi_buffer;
bool half_resolution = false;
GiShaderRD shader;
@@ -659,14 +658,14 @@ public:
SDFGI *create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size);
- void setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used, RendererSceneRenderRD *p_scene_render);
- void process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, RendererSceneRenderRD *p_scene_render);
+ void setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render);
+ void process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render);
- RID gi_probe_instance_create(RID p_base);
- void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);
- bool gi_probe_needs_update(RID p_probe) const;
- void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
- void debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
+ RID voxel_gi_instance_create(RID p_base);
+ void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform);
+ bool voxel_gi_needs_update(RID p_probe) const;
+ void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
+ void debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
};
#endif /* !RENDERING_SERVER_SCENE_GI_RD_H */
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 1f01de1333..ae8d91a73b 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -48,8 +48,8 @@ void get_vogel_disk(float *r_kernel, int p_sample_count) {
}
void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_environment);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
bool needs_sdfgi = env && env->sdfgi_enabled;
if (!needs_sdfgi) {
@@ -83,7 +83,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment
}
int RendererSceneRenderRD::sdfgi_get_pending_region_count(RID p_render_buffers) const {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(rb == nullptr, 0);
@@ -113,7 +113,7 @@ AABB RendererSceneRenderRD::sdfgi_get_pending_region_bounds(RID p_render_buffers
AABB bounds;
Vector3i from;
Vector3i size;
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(rb == nullptr, AABB());
ERR_FAIL_COND_V(rb->sdfgi == nullptr, AABB());
@@ -126,7 +126,7 @@ uint32_t RendererSceneRenderRD::sdfgi_get_pending_region_cascade(RID p_render_bu
AABB bounds;
Vector3i from;
Vector3i size;
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(rb == nullptr, -1);
ERR_FAIL_COND_V(rb->sdfgi == nullptr, -1);
@@ -164,139 +164,133 @@ void RendererSceneRenderRD::environment_initialize(RID p_rid) {
}
void RendererSceneRenderRD::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->background = p_bg;
}
void RendererSceneRenderRD::environment_set_sky(RID p_env, RID p_sky) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->sky = p_sky;
}
void RendererSceneRenderRD::environment_set_sky_custom_fov(RID p_env, float p_scale) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->sky_custom_fov = p_scale;
}
void RendererSceneRenderRD::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->sky_orientation = p_orientation;
}
void RendererSceneRenderRD::environment_set_bg_color(RID p_env, const Color &p_color) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->bg_color = p_color;
}
void RendererSceneRenderRD::environment_set_bg_energy(RID p_env, float p_energy) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->bg_energy = p_energy;
}
void RendererSceneRenderRD::environment_set_canvas_max_layer(RID p_env, int p_max_layer) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->canvas_max_layer = p_max_layer;
}
-void RendererSceneRenderRD::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+void RendererSceneRenderRD::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source) {
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
- env->set_ambient_light(p_color, p_ambient, p_energy, p_sky_contribution, p_reflection_source, p_ao_color);
+ env->set_ambient_light(p_color, p_ambient, p_energy, p_sky_contribution, p_reflection_source);
}
RS::EnvironmentBG RendererSceneRenderRD::environment_get_background(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, RS::ENV_BG_MAX);
return env->background;
}
RID RendererSceneRenderRD::environment_get_sky(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, RID());
return env->sky;
}
float RendererSceneRenderRD::environment_get_sky_custom_fov(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->sky_custom_fov;
}
Basis RendererSceneRenderRD::environment_get_sky_orientation(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, Basis());
return env->sky_orientation;
}
Color RendererSceneRenderRD::environment_get_bg_color(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, Color());
return env->bg_color;
}
float RendererSceneRenderRD::environment_get_bg_energy(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->bg_energy;
}
int RendererSceneRenderRD::environment_get_canvas_max_layer(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->canvas_max_layer;
}
Color RendererSceneRenderRD::environment_get_ambient_light_color(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, Color());
return env->ambient_light;
}
RS::EnvironmentAmbientSource RendererSceneRenderRD::environment_get_ambient_source(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, RS::ENV_AMBIENT_SOURCE_BG);
return env->ambient_source;
}
float RendererSceneRenderRD::environment_get_ambient_light_energy(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->ambient_light_energy;
}
float RendererSceneRenderRD::environment_get_ambient_sky_contribution(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->ambient_sky_contribution;
}
RS::EnvironmentReflectionSource RendererSceneRenderRD::environment_get_reflection_source(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, RS::ENV_REFLECTION_SOURCE_DISABLED);
return env->reflection_source;
}
-Color RendererSceneRenderRD::environment_get_ao_color(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, Color());
- return env->ao_color;
-}
-
void RendererSceneRenderRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->set_tonemap(p_tone_mapper, p_exposure, p_white, p_auto_exposure, p_min_luminance, p_max_luminance, p_auto_exp_speed, p_auto_exp_scale);
}
void RendererSceneRenderRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->set_glow(p_enable, p_levels, p_intensity, p_strength, p_mix, p_bloom_threshold, p_blend_mode, p_hdr_bleed_threshold, p_hdr_bleed_scale, p_hdr_luminance_cap);
}
@@ -310,7 +304,7 @@ void RendererSceneRenderRD::environment_glow_set_use_high_quality(bool p_enable)
}
void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
if (!is_dynamic_gi_supported()) {
@@ -321,65 +315,65 @@ void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::
}
void RendererSceneRenderRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->set_fog(p_enable, p_light_color, p_light_energy, p_sun_scatter, p_density, p_height, p_height_density, p_fog_aerial_perspective);
}
bool RendererSceneRenderRD::environment_is_fog_enabled(RID p_env) const {
- const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, false);
return env->fog_enabled;
}
Color RendererSceneRenderRD::environment_get_fog_light_color(RID p_env) const {
- const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, Color());
return env->fog_light_color;
}
float RendererSceneRenderRD::environment_get_fog_light_energy(RID p_env) const {
- const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_light_energy;
}
float RendererSceneRenderRD::environment_get_fog_sun_scatter(RID p_env) const {
- const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_sun_scatter;
}
float RendererSceneRenderRD::environment_get_fog_density(RID p_env) const {
- const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_density;
}
float RendererSceneRenderRD::environment_get_fog_height(RID p_env) const {
- const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_height;
}
float RendererSceneRenderRD::environment_get_fog_height_density(RID p_env) const {
- const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_height_density;
}
float RendererSceneRenderRD::environment_get_fog_aerial_perspective(RID p_env) const {
- const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_aerial_perspective;
}
-void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) {
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
if (!is_volumetric_supported()) {
return;
}
- env->set_volumetric_fog(p_enable, p_density, p_light, p_light_energy, p_length, p_detail_spread, p_gi_inject, p_temporal_reprojection, p_temporal_reprojection_amount);
+ env->set_volumetric_fog(p_enable, p_density, p_albedo, p_emission, p_emission_energy, p_anisotropy, p_length, p_detail_spread, p_gi_inject, p_temporal_reprojection, p_temporal_reprojection_amount, p_ambient_inject);
}
void RendererSceneRenderRD::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) {
@@ -403,7 +397,7 @@ void RendererSceneRenderRD::environment_set_sdfgi_frames_to_update_light(RS::Env
}
void RendererSceneRenderRD::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->set_ssr(p_enable, p_max_steps, p_fade_int, p_fade_out, p_depth_tolerance);
@@ -418,7 +412,7 @@ RS::EnvironmentSSRRoughnessQuality RendererSceneRenderRD::environment_get_ssr_ro
}
void RendererSceneRenderRD::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->set_ssao(p_enable, p_radius, p_intensity, p_power, p_detail, p_horizon, p_sharpness, p_light_affect, p_ao_channel_affect);
@@ -434,30 +428,30 @@ void RendererSceneRenderRD::environment_set_ssao_quality(RS::EnvironmentSSAOQual
}
bool RendererSceneRenderRD::environment_is_ssao_enabled(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, false);
return env->ssao_enabled;
}
float RendererSceneRenderRD::environment_get_ssao_ao_affect(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, 0.0);
return env->ssao_ao_channel_affect;
}
float RendererSceneRenderRD::environment_get_ssao_light_affect(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, 0.0);
return env->ssao_direct_light_affect;
}
bool RendererSceneRenderRD::environment_is_ssr_enabled(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, false);
return env->ssr_enabled;
}
bool RendererSceneRenderRD::environment_is_sdfgi_enabled(RID p_env) const {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, false);
return env->sdfgi_enabled;
}
@@ -467,7 +461,7 @@ bool RendererSceneRenderRD::is_environment(RID p_env) const {
}
Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, Ref<Image>());
if (env->background == RS::ENV_BG_CAMERA_FEED || env->background == RS::ENV_BG_CANVAS || env->background == RS::ENV_BG_KEEP) {
@@ -486,7 +480,7 @@ Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba
color.b *= env->bg_energy;
Ref<Image> ret;
- ret.instance();
+ ret.instantiate();
ret->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF);
for (int i = 0; i < p_size.width; i++) {
for (int j = 0; j < p_size.height; j++) {
@@ -505,6 +499,37 @@ Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba
////////////////////////////////////////////////////////////
+RID RendererSceneRenderRD::fog_volume_instance_create(RID p_fog_volume) {
+ FogVolumeInstance fvi;
+ fvi.volume = p_fog_volume;
+ return fog_volume_instance_owner.make_rid(fvi);
+}
+void RendererSceneRenderRD::fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) {
+ FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
+ ERR_FAIL_COND(!fvi);
+ fvi->transform = p_transform;
+}
+void RendererSceneRenderRD::fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) {
+ FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
+ ERR_FAIL_COND(!fvi);
+ fvi->active = p_active;
+}
+
+RID RendererSceneRenderRD::fog_volume_instance_get_volume(RID p_fog_volume_instance) const {
+ FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
+ ERR_FAIL_COND_V(!fvi, RID());
+ return fvi->volume;
+}
+
+Vector3 RendererSceneRenderRD::fog_volume_instance_get_position(RID p_fog_volume_instance) const {
+ FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
+ ERR_FAIL_COND_V(!fvi, Vector3());
+
+ return fvi->transform.get_origin();
+}
+
+////////////////////////////////////////////////////////////
+
RID RendererSceneRenderRD::reflection_atlas_create() {
ReflectionAtlas ra;
ra.count = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_count");
@@ -522,7 +547,7 @@ RID RendererSceneRenderRD::reflection_atlas_create() {
}
void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) {
- ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_ref_atlas);
+ ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas);
ERR_FAIL_COND(!ra);
if (ra->size == p_reflection_size && ra->count == p_reflection_count) {
@@ -557,7 +582,7 @@ void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_ref
}
int RendererSceneRenderRD::reflection_atlas_get_size(RID p_ref_atlas) const {
- ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_ref_atlas);
+ ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas);
ERR_FAIL_COND_V(!ra, 0);
return ra->size;
@@ -567,11 +592,13 @@ int RendererSceneRenderRD::reflection_atlas_get_size(RID p_ref_atlas) const {
RID RendererSceneRenderRD::reflection_probe_instance_create(RID p_probe) {
ReflectionProbeInstance rpi;
rpi.probe = p_probe;
+ rpi.forward_id = _allocate_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE);
+
return reflection_probe_instance_owner.make_rid(rpi);
}
-void RendererSceneRenderRD::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+void RendererSceneRenderRD::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!rpi);
rpi->transform = p_transform;
@@ -579,13 +606,13 @@ void RendererSceneRenderRD::reflection_probe_instance_set_transform(RID p_instan
}
void RendererSceneRenderRD::reflection_probe_release_atlas_index(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!rpi);
if (rpi->atlas.is_null()) {
return; //nothing to release
}
- ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
ERR_FAIL_COND(!atlas);
ERR_FAIL_INDEX(rpi->atlas_index, atlas->reflections.size());
atlas->reflections.write[rpi->atlas_index].owner = RID();
@@ -594,7 +621,7 @@ void RendererSceneRenderRD::reflection_probe_release_atlas_index(RID p_instance)
}
bool RendererSceneRenderRD::reflection_probe_instance_needs_redraw(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!rpi, false);
if (rpi->rendering) {
@@ -613,20 +640,22 @@ bool RendererSceneRenderRD::reflection_probe_instance_needs_redraw(RID p_instanc
}
bool RendererSceneRenderRD::reflection_probe_instance_has_reflection(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!rpi, false);
return rpi->atlas.is_valid();
}
bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
- ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_reflection_atlas);
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_reflection_atlas);
ERR_FAIL_COND_V(!atlas, false);
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!rpi, false);
+ RD::get_singleton()->draw_command_begin_label("Reflection probe render");
+
if (storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->size != 256) {
WARN_PRINT("ReflectionProbes set to UPDATE_ALWAYS must have an atlas size of 256. Please update the atlas size in the ProjectSettings.");
reflection_atlas_set_size(p_reflection_atlas, 256, atlas->count);
@@ -654,12 +683,12 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
//reflection atlas was unused, create:
RD::TextureFormat tf;
tf.array_layers = 6 * atlas->count;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.format = _render_buffers_get_color_format();
tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
tf.mipmaps = mipmaps;
tf.width = atlas->size;
tf.height = atlas->size;
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
atlas->reflection = RD::get_singleton()->texture_create(tf, RD::TextureView());
}
@@ -673,12 +702,9 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
}
atlas->reflections.resize(atlas->count);
for (int i = 0; i < atlas->count; i++) {
- atlas->reflections.write[i].data.update_reflection_data(atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers);
+ atlas->reflections.write[i].data.update_reflection_data(storage, atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers, _render_buffers_get_color_format());
for (int j = 0; j < 6; j++) {
- Vector<RID> fb;
- fb.push_back(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j]);
- fb.push_back(atlas->depth_buffer);
- atlas->reflections.write[i].fbs[j] = RD::get_singleton()->framebuffer_create(fb);
+ atlas->reflections.write[i].fbs[j] = reflection_probe_create_framebuffer(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j], atlas->depth_buffer);
}
}
@@ -700,7 +726,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
uint64_t pass_min = 0;
for (int i = 0; i < atlas->reflections.size(); i++) {
- ReflectionProbeInstance *rpi2 = reflection_probe_instance_owner.getornull(atlas->reflections[i].owner);
+ ReflectionProbeInstance *rpi2 = reflection_probe_instance_owner.get_or_null(atlas->reflections[i].owner);
if (rpi2->last_pass < pass_min) {
pass_min = rpi2->last_pass;
rpi->atlas_index = i;
@@ -709,22 +735,35 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
}
}
+ if (rpi->atlas_index != -1) { // should we fail if this is still -1 ?
+ atlas->reflections.write[rpi->atlas_index].owner = p_instance;
+ }
+
rpi->atlas = p_reflection_atlas;
rpi->rendering = true;
rpi->dirty = false;
rpi->processing_layer = 1;
rpi->processing_side = 0;
+ RD::get_singleton()->draw_command_end_label();
+
return true;
}
+RID RendererSceneRenderRD::reflection_probe_create_framebuffer(RID p_color, RID p_depth) {
+ Vector<RID> fb;
+ fb.push_back(p_color);
+ fb.push_back(p_depth);
+ return RD::get_singleton()->framebuffer_create(fb);
+}
+
bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!rpi, false);
ERR_FAIL_COND_V(!rpi->rendering, false);
ERR_FAIL_COND_V(rpi->atlas.is_null(), false);
- ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
if (!atlas || rpi->atlas_index == -1) {
//does not belong to an atlas anymore, cancel (was removed from atlas or atlas changed while rendering)
rpi->rendering = false;
@@ -765,30 +804,30 @@ bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_ins
}
uint32_t RendererSceneRenderRD::reflection_probe_instance_get_resolution(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!rpi, 0);
- ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
ERR_FAIL_COND_V(!atlas, 0);
return atlas->size;
}
RID RendererSceneRenderRD::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!rpi, RID());
ERR_FAIL_INDEX_V(p_index, 6, RID());
- ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
ERR_FAIL_COND_V(!atlas, RID());
return atlas->reflections[rpi->atlas_index].fbs[p_index];
}
RID RendererSceneRenderRD::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!rpi, RID());
ERR_FAIL_INDEX_V(p_index, 6, RID());
- ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
ERR_FAIL_COND_V(!atlas, RID());
return atlas->depth_fb;
}
@@ -815,7 +854,7 @@ void RendererSceneRenderRD::_update_shadow_atlas(ShadowAtlas *shadow_atlas) {
}
void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
ERR_FAIL_COND(!shadow_atlas);
ERR_FAIL_COND(p_size < 0);
p_size = next_power_of_2(p_size);
@@ -836,8 +875,8 @@ void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool
}
//erase shadow atlas reference from lights
- for (Map<RID, uint32_t>::Element *E = shadow_atlas->shadow_owners.front(); E; E = E->next()) {
- LightInstance *li = light_instance_owner.getornull(E->key());
+ for (const KeyValue<RID, uint32_t> &E : shadow_atlas->shadow_owners) {
+ LightInstance *li = light_instance_owner.get_or_null(E.key);
ERR_CONTINUE(!li);
li->shadow_atlases.erase(p_atlas);
}
@@ -846,11 +885,11 @@ void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool
shadow_atlas->shadow_owners.clear();
shadow_atlas->size = p_size;
- shadow_atlas->use_16_bits = p_size;
+ shadow_atlas->use_16_bits = p_16_bits;
}
void RendererSceneRenderRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
ERR_FAIL_COND(!shadow_atlas);
ERR_FAIL_INDEX(p_quadrant, 4);
ERR_FAIL_INDEX(p_subdivision, 16384);
@@ -872,7 +911,7 @@ void RendererSceneRenderRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, i
for (int i = 0; i < shadow_atlas->quadrants[p_quadrant].shadows.size(); i++) {
if (shadow_atlas->quadrants[p_quadrant].shadows[i].owner.is_valid()) {
shadow_atlas->shadow_owners.erase(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
- LightInstance *li = light_instance_owner.getornull(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
+ LightInstance *li = light_instance_owner.get_or_null(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
ERR_CONTINUE(!li);
li->shadow_atlases.erase(p_atlas);
}
@@ -921,7 +960,7 @@ bool RendererSceneRenderRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas,
//look for an empty space
int sc = shadow_atlas->quadrants[qidx].shadows.size();
- ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptrw();
+ const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr();
int found_free_idx = -1; //found a free one
int found_used_idx = -1; //found existing one, must steal it
@@ -933,7 +972,7 @@ bool RendererSceneRenderRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas,
break;
}
- LightInstance *sli = light_instance_owner.getornull(sarr[j].owner);
+ LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner);
ERR_CONTINUE(!sli);
if (sli->last_scene_pass != scene_pass) {
@@ -966,11 +1005,83 @@ bool RendererSceneRenderRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas,
return false;
}
+bool RendererSceneRenderRD::_shadow_atlas_find_omni_shadows(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) {
+ for (int i = p_quadrant_count - 1; i >= 0; i--) {
+ int qidx = p_in_quadrants[i];
+
+ if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) {
+ return false;
+ }
+
+ //look for an empty space
+ int sc = shadow_atlas->quadrants[qidx].shadows.size();
+ const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr();
+
+ int found_idx = -1;
+ uint64_t min_pass = 0; // sum of currently selected spots, try to get the least recently used pair
+
+ for (int j = 0; j < sc - 1; j++) {
+ uint64_t pass = 0;
+
+ if (sarr[j].owner.is_valid()) {
+ LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner);
+ ERR_CONTINUE(!sli);
+
+ if (sli->last_scene_pass == scene_pass) {
+ continue;
+ }
+
+ //was just allocated, don't kill it so soon, wait a bit..
+ if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) {
+ continue;
+ }
+ pass += sli->last_scene_pass;
+ }
+
+ if (sarr[j + 1].owner.is_valid()) {
+ LightInstance *sli = light_instance_owner.get_or_null(sarr[j + 1].owner);
+ ERR_CONTINUE(!sli);
+
+ if (sli->last_scene_pass == scene_pass) {
+ continue;
+ }
+
+ //was just allocated, don't kill it so soon, wait a bit..
+ if (p_tick - sarr[j + 1].alloc_tick < shadow_atlas_realloc_tolerance_msec) {
+ continue;
+ }
+ pass += sli->last_scene_pass;
+ }
+
+ if (found_idx == -1 || pass < min_pass) {
+ found_idx = j;
+ min_pass = pass;
+
+ // we found two empty spots, no need to check the rest
+ if (pass == 0) {
+ break;
+ }
+ }
+ }
+
+ if (found_idx == -1) {
+ continue; //nothing found
+ }
+
+ r_quadrant = qidx;
+ r_shadow = found_idx;
+
+ return true;
+ }
+
+ return false;
+}
+
bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) {
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
ERR_FAIL_COND_V(!shadow_atlas, false);
- LightInstance *li = light_instance_owner.getornull(p_light_intance);
+ LightInstance *li = light_instance_owner.get_or_null(p_light_intance);
ERR_FAIL_COND_V(!li, false);
if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) {
@@ -1011,94 +1122,104 @@ bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_i
uint64_t tick = OS::get_singleton()->get_ticks_msec();
- //see if it already exists
+ uint32_t old_key = ShadowAtlas::SHADOW_INVALID;
+ uint32_t old_quadrant = ShadowAtlas::SHADOW_INVALID;
+ uint32_t old_shadow = ShadowAtlas::SHADOW_INVALID;
+ int old_subdivision = -1;
+
+ bool should_realloc = false;
+ bool should_redraw = false;
if (shadow_atlas->shadow_owners.has(p_light_intance)) {
- //it does!
- uint32_t key = shadow_atlas->shadow_owners[p_light_intance];
- uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
- uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK;
+ old_key = shadow_atlas->shadow_owners[p_light_intance];
+ old_quadrant = (old_key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
+ old_shadow = old_key & ShadowAtlas::SHADOW_INDEX_MASK;
- bool should_realloc = shadow_atlas->quadrants[q].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec);
- bool should_redraw = shadow_atlas->quadrants[q].shadows[s].version != p_light_version;
+ should_realloc = shadow_atlas->quadrants[old_quadrant].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec);
+ should_redraw = shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].version != p_light_version;
if (!should_realloc) {
- shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version;
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = p_light_version;
//already existing, see if it should redraw or it's just OK
return should_redraw;
}
- int new_quadrant, new_shadow;
+ old_subdivision = shadow_atlas->quadrants[old_quadrant].subdivision;
+ }
- //find a better place
- if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, shadow_atlas->quadrants[q].subdivision, tick, new_quadrant, new_shadow)) {
- //found a better place!
- ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
- if (sh->owner.is_valid()) {
- //is taken, but is invalid, erasing it
- shadow_atlas->shadow_owners.erase(sh->owner);
- LightInstance *sli = light_instance_owner.getornull(sh->owner);
- sli->shadow_atlases.erase(p_atlas);
- }
+ bool is_omni = li->light_type == RS::LIGHT_OMNI;
+ bool found_shadow = false;
+ int new_quadrant = -1;
+ int new_shadow = -1;
- //erase previous
- shadow_atlas->quadrants[q].shadows.write[s].version = 0;
- shadow_atlas->quadrants[q].shadows.write[s].owner = RID();
+ if (is_omni) {
+ found_shadow = _shadow_atlas_find_omni_shadows(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, new_quadrant, new_shadow);
+ } else {
+ found_shadow = _shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, new_quadrant, new_shadow);
+ }
- sh->owner = p_light_intance;
- sh->alloc_tick = tick;
- sh->version = p_light_version;
- li->shadow_atlases.insert(p_atlas);
-
- //make new key
- key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT;
- key |= new_shadow;
- //update it in map
- shadow_atlas->shadow_owners[p_light_intance] = key;
- //make it dirty, as it should redraw anyway
- return true;
+ if (found_shadow) {
+ if (old_quadrant != ShadowAtlas::SHADOW_INVALID) {
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = 0;
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].owner = RID();
+
+ if (old_key & ShadowAtlas::OMNI_LIGHT_FLAG) {
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow + 1].version = 0;
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow + 1].owner = RID();
+ }
}
- //no better place for this shadow found, keep current
+ uint32_t new_key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT;
+ new_key |= new_shadow;
- //already existing, see if it should redraw or it's just OK
+ ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
+ _shadow_atlas_invalidate_shadow(sh, p_atlas, shadow_atlas, new_quadrant, new_shadow);
- shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version;
+ sh->owner = p_light_intance;
+ sh->alloc_tick = tick;
+ sh->version = p_light_version;
- return should_redraw;
- }
+ if (is_omni) {
+ new_key |= ShadowAtlas::OMNI_LIGHT_FLAG;
- int new_quadrant, new_shadow;
+ int new_omni_shadow = new_shadow + 1;
+ ShadowAtlas::Quadrant::Shadow *extra_sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_omni_shadow];
+ _shadow_atlas_invalidate_shadow(extra_sh, p_atlas, shadow_atlas, new_quadrant, new_omni_shadow);
- //find a better place
- if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, -1, tick, new_quadrant, new_shadow)) {
- //found a better place!
- ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
- if (sh->owner.is_valid()) {
- //is taken, but is invalid, erasing it
- shadow_atlas->shadow_owners.erase(sh->owner);
- LightInstance *sli = light_instance_owner.getornull(sh->owner);
- sli->shadow_atlases.erase(p_atlas);
+ extra_sh->owner = p_light_intance;
+ extra_sh->alloc_tick = tick;
+ extra_sh->version = p_light_version;
}
- sh->owner = p_light_intance;
- sh->alloc_tick = tick;
- sh->version = p_light_version;
li->shadow_atlases.insert(p_atlas);
- //make new key
- uint32_t key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT;
- key |= new_shadow;
//update it in map
- shadow_atlas->shadow_owners[p_light_intance] = key;
+ shadow_atlas->shadow_owners[p_light_intance] = new_key;
//make it dirty, as it should redraw anyway
-
return true;
}
- //no place to allocate this light, apologies
+ return should_redraw;
+}
- return false;
+void RendererSceneRenderRD::_shadow_atlas_invalidate_shadow(RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, RendererSceneRenderRD::ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx) {
+ if (p_shadow->owner.is_valid()) {
+ LightInstance *sli = light_instance_owner.get_or_null(p_shadow->owner);
+ uint32_t old_key = p_shadow_atlas->shadow_owners[p_shadow->owner];
+
+ if (old_key & ShadowAtlas::OMNI_LIGHT_FLAG) {
+ uint32_t s = old_key & ShadowAtlas::SHADOW_INDEX_MASK;
+ uint32_t omni_shadow_idx = p_shadow_idx + (s == (uint32_t)p_shadow_idx ? 1 : -1);
+ RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *omni_shadow = &p_shadow_atlas->quadrants[p_quadrant].shadows.write[omni_shadow_idx];
+ omni_shadow->version = 0;
+ omni_shadow->owner = RID();
+ }
+
+ p_shadow->version = 0;
+ p_shadow->owner = RID();
+ sli->shadow_atlases.erase(p_atlas);
+ p_shadow_atlas->shadow_owners.erase(p_shadow->owner);
+ }
}
void RendererSceneRenderRD::_update_directional_shadow_atlas() {
@@ -1123,6 +1244,7 @@ void RendererSceneRenderRD::directional_shadow_atlas_set_size(int p_size, bool p
}
directional_shadow.size = p_size;
+ directional_shadow.use_16_bits = p_16_bits;
if (directional_shadow.depth.is_valid()) {
RD::get_singleton()->free(directional_shadow.depth);
@@ -1163,7 +1285,7 @@ int RendererSceneRenderRD::get_directional_light_shadow_size(RID p_light_intance
Rect2i r = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, 0);
- LightInstance *light_instance = light_instance_owner.getornull(p_light_intance);
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_intance);
ERR_FAIL_COND_V(!light_instance, 0);
switch (storage->light_directional_get_shadow_mode(light_instance->light)) {
@@ -1199,7 +1321,7 @@ void RendererSceneRenderRD::camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokeh
}
void RendererSceneRenderRD::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) {
- CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
+ CameraEffects *camfx = camera_effects_owner.get_or_null(p_camera_effects);
ERR_FAIL_COND(!camfx);
camfx->dof_blur_far_enabled = p_far_enable;
@@ -1214,7 +1336,7 @@ void RendererSceneRenderRD::camera_effects_set_dof_blur(RID p_camera_effects, bo
}
void RendererSceneRenderRD::camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) {
- CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
+ CameraEffects *camfx = camera_effects_owner.get_or_null(p_camera_effects);
ERR_FAIL_COND(!camfx);
camfx->override_exposure_enabled = p_enable;
@@ -1224,31 +1346,34 @@ void RendererSceneRenderRD::camera_effects_set_custom_exposure(RID p_camera_effe
RID RendererSceneRenderRD::light_instance_create(RID p_light) {
RID li = light_instance_owner.make_rid(LightInstance());
- LightInstance *light_instance = light_instance_owner.getornull(li);
+ LightInstance *light_instance = light_instance_owner.get_or_null(li);
light_instance->self = li;
light_instance->light = p_light;
light_instance->light_type = storage->light_get_type(p_light);
+ if (light_instance->light_type != RS::LIGHT_DIRECTIONAL) {
+ light_instance->forward_id = _allocate_forward_id(light_instance->light_type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT);
+ }
return li;
}
-void RendererSceneRenderRD::light_instance_set_transform(RID p_light_instance, const Transform &p_transform) {
- LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
+void RendererSceneRenderRD::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
ERR_FAIL_COND(!light_instance);
light_instance->transform = p_transform;
}
void RendererSceneRenderRD::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) {
- LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
ERR_FAIL_COND(!light_instance);
light_instance->aabb = p_aabb;
}
-void RendererSceneRenderRD::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);
+void RendererSceneRenderRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &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.get_or_null(p_light_instance);
ERR_FAIL_COND(!light_instance);
ERR_FAIL_INDEX(p_pass, 6);
@@ -1264,7 +1389,7 @@ void RendererSceneRenderRD::light_instance_set_shadow_transform(RID p_light_inst
}
void RendererSceneRenderRD::light_instance_mark_visible(RID p_light_instance) {
- LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
ERR_FAIL_COND(!light_instance);
light_instance->last_scene_pass = scene_pass;
@@ -1302,11 +1427,12 @@ RendererSceneRenderRD::ShadowCubemap *RendererSceneRenderRD::_get_shadow_cubemap
RID RendererSceneRenderRD::decal_instance_create(RID p_decal) {
DecalInstance di;
di.decal = p_decal;
+ di.forward_id = _allocate_forward_id(FORWARD_ID_TYPE_DECAL);
return decal_instance_owner.make_rid(di);
}
-void RendererSceneRenderRD::decal_instance_set_transform(RID p_decal, const Transform &p_transform) {
- DecalInstance *di = decal_instance_owner.getornull(p_decal);
+void RendererSceneRenderRD::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) {
+ DecalInstance *di = decal_instance_owner.get_or_null(p_decal);
ERR_FAIL_COND(!di);
di->transform = p_transform;
}
@@ -1318,40 +1444,40 @@ RID RendererSceneRenderRD::lightmap_instance_create(RID p_lightmap) {
li.lightmap = p_lightmap;
return lightmap_instance_owner.make_rid(li);
}
-void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) {
- LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap);
+void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) {
+ LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap);
ERR_FAIL_COND(!li);
li->transform = p_transform;
}
/////////////////////////////////
-RID RendererSceneRenderRD::gi_probe_instance_create(RID p_base) {
- return gi.gi_probe_instance_create(p_base);
+RID RendererSceneRenderRD::voxel_gi_instance_create(RID p_base) {
+ return gi.voxel_gi_instance_create(p_base);
}
-void RendererSceneRenderRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {
- gi.gi_probe_instance_set_transform_to_data(p_probe, p_xform);
+void RendererSceneRenderRD::voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) {
+ gi.voxel_gi_instance_set_transform_to_data(p_probe, p_xform);
}
-bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const {
+bool RendererSceneRenderRD::voxel_gi_needs_update(RID p_probe) const {
if (!is_dynamic_gi_supported()) {
return false;
}
- return gi.gi_probe_needs_update(p_probe);
+ return gi.voxel_gi_needs_update(p_probe);
}
-void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) {
+void RendererSceneRenderRD::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) {
if (!is_dynamic_gi_supported()) {
return;
}
- gi.gi_probe_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects, this);
+ gi.voxel_gi_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects, this);
}
void RendererSceneRenderRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND(!rb);
if (!rb->sdfgi) {
@@ -1373,14 +1499,26 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) {
uint32_t mipmaps_required = Image::get_image_required_mipmaps(rb->width, rb->height, Image::FORMAT_RGBAH);
+ // TODO make sure texture_create_shared_from_slice works for multiview
+
RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.width = rb->width;
- tf.height = rb->height;
- tf.texture_type = RD::TEXTURE_TYPE_2D;
- tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ tf.format = _render_buffers_get_color_format(); // RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.width = rb->internal_width;
+ tf.height = rb->internal_height;
+ tf.texture_type = rb->view_count > 1 ? RD::TEXTURE_TYPE_2D_ARRAY : RD::TEXTURE_TYPE_2D;
+ tf.array_layers = rb->view_count;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ if (_render_buffers_can_be_storage()) {
+ tf.usage_bits += RD::TEXTURE_USAGE_STORAGE_BIT;
+ } else {
+ tf.usage_bits += RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
tf.mipmaps = mipmaps_required;
+ rb->sss_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ tf.width = rb->internal_width;
+ tf.height = rb->internal_height;
rb->blur[0].texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
//the second one is smaller (only used for separatable part of blur)
tf.width >>= 1;
@@ -1388,8 +1526,8 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) {
tf.mipmaps--;
rb->blur[1].texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
- int base_width = rb->width;
- int base_height = rb->height;
+ int base_width = rb->internal_width;
+ int base_height = rb->internal_height;
for (uint32_t i = 0; i < mipmaps_required; i++) {
RenderBuffers::Blur::Mipmap mm;
@@ -1398,24 +1536,132 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) {
mm.width = base_width;
mm.height = base_height;
+ if (!_render_buffers_can_be_storage()) {
+ Vector<RID> fb;
+ fb.push_back(mm.texture);
+
+ mm.fb = RD::get_singleton()->framebuffer_create(fb);
+ }
+
+ if (!_render_buffers_can_be_storage()) {
+ // and half texture, this is an intermediate result so just allocate a texture, is this good enough?
+ tf.width = MAX(1, base_width >> 1);
+ tf.height = base_height;
+ tf.mipmaps = 1; // 1 or 0?
+
+ mm.half_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ Vector<RID> half_fb;
+ half_fb.push_back(mm.half_texture);
+ mm.half_fb = RD::get_singleton()->framebuffer_create(half_fb);
+ }
+
rb->blur[0].mipmaps.push_back(mm);
if (i > 0) {
mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->blur[1].texture, 0, i - 1);
+ if (!_render_buffers_can_be_storage()) {
+ Vector<RID> fb;
+ fb.push_back(mm.texture);
+
+ mm.fb = RD::get_singleton()->framebuffer_create(fb);
+
+ // We can re-use the half texture here as it is an intermediate result
+ }
+
rb->blur[1].mipmaps.push_back(mm);
}
base_width = MAX(1, base_width >> 1);
base_height = MAX(1, base_height >> 1);
}
+
+ if (!_render_buffers_can_be_storage()) {
+ // create 4 weight textures, 2 full size, 2 half size
+
+ tf.format = RD::DATA_FORMAT_R16_SFLOAT; // We could probably use DATA_FORMAT_R8_SNORM if we don't pre-multiply by blur_size but that depends on whether we can remove DEPTH_GAP
+ tf.width = rb->internal_width;
+ tf.height = rb->internal_height;
+ tf.texture_type = rb->view_count > 1 ? RD::TEXTURE_TYPE_2D_ARRAY : RD::TEXTURE_TYPE_2D;
+ tf.array_layers = rb->view_count;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ tf.mipmaps = 1;
+ for (uint32_t i = 0; i < 4; i++) {
+ // associated blur texture
+ RID texture;
+ if (i == 0) {
+ texture = rb->texture;
+ } else if (i == 1) {
+ texture = rb->blur[0].mipmaps[0].texture;
+ } else if (i == 2) {
+ texture = rb->blur[1].mipmaps[0].texture;
+ } else if (i == 3) {
+ texture = rb->blur[0].mipmaps[1].texture;
+ }
+
+ // create weight texture
+ rb->weight_buffers[i].weight = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ // create frame buffer
+ Vector<RID> fb;
+ fb.push_back(texture);
+ fb.push_back(rb->weight_buffers[i].weight);
+ rb->weight_buffers[i].fb = RD::get_singleton()->framebuffer_create(fb);
+
+ if (i == 1) {
+ // next 2 are half size
+ tf.width = MAX(1, tf.width >> 1);
+ tf.height = MAX(1, tf.height >> 1);
+ }
+ }
+
+ {
+ // and finally an FB for just our base weights
+ Vector<RID> fb;
+ fb.push_back(rb->weight_buffers[0].weight);
+ rb->base_weight_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
+ }
+}
+
+void RendererSceneRenderRD::_allocate_depth_backbuffer_textures(RenderBuffers *rb) {
+ ERR_FAIL_COND(!rb->depth_back_texture.is_null());
+
+ {
+ RD::TextureFormat tf;
+ if (rb->view_count > 1) {
+ tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ }
+ // We're not using this as a depth stencil, just copying our data into this. May need to look into using a different format on mobile, maybe R16?
+ tf.format = RD::DATA_FORMAT_R32_SFLOAT;
+
+ tf.width = rb->width;
+ tf.height = rb->height;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
+ tf.array_layers = rb->view_count; // create a layer for every view
+
+ tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; // set this as color attachment because we're copying data into it, it's not actually used as a depth buffer
+
+ rb->depth_back_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+
+ if (!_render_buffers_can_be_storage()) {
+ // create framebuffer so we can write into this...
+
+ Vector<RID> fb;
+ fb.push_back(rb->depth_back_texture);
+
+ rb->depth_back_fb = RD::get_singleton()->framebuffer_create(fb, RD::INVALID_ID, rb->view_count);
+ }
}
void RendererSceneRenderRD::_allocate_luminance_textures(RenderBuffers *rb) {
ERR_FAIL_COND(!rb->luminance.current.is_null());
- int w = rb->width;
- int h = rb->height;
+ int w = rb->internal_width;
+ int h = rb->internal_height;
while (true) {
w = MAX(w / 8, 1);
@@ -1425,29 +1671,68 @@ void RendererSceneRenderRD::_allocate_luminance_textures(RenderBuffers *rb) {
tf.format = RD::DATA_FORMAT_R32_SFLOAT;
tf.width = w;
tf.height = h;
- tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
bool final = w == 1 && h == 1;
- if (final) {
- tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT;
+ if (_render_buffers_can_be_storage()) {
+ tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
+ if (final) {
+ tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT;
+ }
+ } else {
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
}
RID texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
rb->luminance.reduce.push_back(texture);
+ if (!_render_buffers_can_be_storage()) {
+ Vector<RID> fb;
+ fb.push_back(texture);
+
+ rb->luminance.fb.push_back(RD::get_singleton()->framebuffer_create(fb));
+ }
if (final) {
rb->luminance.current = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ if (!_render_buffers_can_be_storage()) {
+ Vector<RID> fb;
+ fb.push_back(rb->luminance.current);
+
+ rb->luminance.current_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
break;
}
}
}
void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) {
- if (rb->texture.is_valid()) {
- RD::get_singleton()->free(rb->texture);
+ if (rb->texture_fb.is_valid()) {
+ RD::get_singleton()->free(rb->texture_fb);
+ rb->texture_fb = RID();
+ }
+
+ if (rb->internal_texture == rb->texture && rb->internal_texture.is_valid()) {
+ RD::get_singleton()->free(rb->internal_texture);
rb->texture = RID();
+ rb->internal_texture = RID();
+ rb->upscale_texture = RID();
+ } else {
+ if (rb->texture.is_valid()) {
+ RD::get_singleton()->free(rb->texture);
+ rb->texture = RID();
+ }
+
+ if (rb->internal_texture.is_valid()) {
+ RD::get_singleton()->free(rb->internal_texture);
+ rb->internal_texture = RID();
+ }
+
+ if (rb->upscale_texture.is_valid()) {
+ RD::get_singleton()->free(rb->upscale_texture);
+ rb->upscale_texture = RID();
+ }
}
if (rb->depth_texture.is_valid()) {
@@ -1455,20 +1740,59 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) {
rb->depth_texture = RID();
}
+ if (rb->depth_back_fb.is_valid()) {
+ RD::get_singleton()->free(rb->depth_back_fb);
+ rb->depth_back_fb = RID();
+ }
+
+ if (rb->depth_back_texture.is_valid()) {
+ RD::get_singleton()->free(rb->depth_back_texture);
+ rb->depth_back_texture = RID();
+ }
+
+ if (rb->sss_texture.is_valid()) {
+ RD::get_singleton()->free(rb->sss_texture);
+ rb->sss_texture = RID();
+ }
+
for (int i = 0; i < 2; i++) {
+ for (int m = 0; m < rb->blur[i].mipmaps.size(); m++) {
+ // do we free the texture slice here? or is it enough to free the main texture?
+
+ // do free the mobile extra stuff
+ if (rb->blur[i].mipmaps[m].fb.is_valid()) {
+ RD::get_singleton()->free(rb->blur[i].mipmaps[m].fb);
+ }
+ if (rb->blur[i].mipmaps[m].half_fb.is_valid()) {
+ RD::get_singleton()->free(rb->blur[i].mipmaps[m].half_fb);
+ }
+ if (rb->blur[i].mipmaps[m].half_texture.is_valid()) {
+ RD::get_singleton()->free(rb->blur[i].mipmaps[m].half_texture);
+ }
+ }
+ rb->blur[i].mipmaps.clear();
+
if (rb->blur[i].texture.is_valid()) {
RD::get_singleton()->free(rb->blur[i].texture);
rb->blur[i].texture = RID();
- rb->blur[i].mipmaps.clear();
}
}
+ for (int i = 0; i < rb->luminance.fb.size(); i++) {
+ RD::get_singleton()->free(rb->luminance.fb[i]);
+ }
+ rb->luminance.fb.clear();
+
for (int i = 0; i < rb->luminance.reduce.size(); i++) {
RD::get_singleton()->free(rb->luminance.reduce[i]);
}
-
rb->luminance.reduce.clear();
+ if (rb->luminance.current_fb.is_valid()) {
+ RD::get_singleton()->free(rb->luminance.current_fb);
+ rb->luminance.current_fb = RID();
+ }
+
if (rb->luminance.current.is_valid()) {
RD::get_singleton()->free(rb->luminance.current);
rb->luminance.current = RID();
@@ -1517,10 +1841,10 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) {
}
void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatrix &p_camera) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND(!rb);
- bool can_use_effects = rb->width >= 8 && rb->height >= 8;
+ bool can_use_effects = rb->internal_width >= 8 && rb->internal_height >= 8;
if (!can_use_effects) {
//just copy
@@ -1531,22 +1855,22 @@ void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatri
_allocate_blur_textures(rb);
}
- storage->get_effects()->sub_surface_scattering(rb->texture, rb->blur[0].mipmaps[0].texture, rb->depth_texture, p_camera, Size2i(rb->width, rb->height), sss_scale, sss_depth_scale, sss_quality);
+ storage->get_effects()->sub_surface_scattering(rb->internal_texture, rb->sss_texture, rb->depth_texture, p_camera, Size2i(rb->internal_width, rb->internal_height), sss_scale, sss_depth_scale, sss_quality);
}
void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND(!rb);
- bool can_use_effects = rb->width >= 8 && rb->height >= 8;
+ bool can_use_effects = rb->internal_width >= 8 && rb->internal_height >= 8;
if (!can_use_effects) {
//just copy
- storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->texture, RID());
+ storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->internal_texture, RID());
return;
}
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_environment);
ERR_FAIL_COND(!env);
ERR_FAIL_COND(!env->ssr_enabled);
@@ -1554,8 +1878,8 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb
if (rb->ssr.depth_scaled.is_null()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R32_SFLOAT;
- tf.width = rb->width / 2;
- tf.height = rb->height / 2;
+ tf.width = rb->internal_width / 2;
+ tf.height = rb->internal_height / 2;
tf.texture_type = RD::TEXTURE_TYPE_2D;
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
@@ -1569,8 +1893,8 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb
if (ssr_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED && !rb->ssr.blur_radius[0].is_valid()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8_UNORM;
- tf.width = rb->width / 2;
- tf.height = rb->height / 2;
+ tf.width = rb->internal_width / 2;
+ tf.height = rb->internal_height / 2;
tf.texture_type = RD::TEXTURE_TYPE_2D;
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
@@ -1582,15 +1906,15 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb
_allocate_blur_textures(rb);
}
- storage->get_effects()->screen_space_reflection(rb->texture, p_normal_buffer, ssr_roughness_quality, rb->ssr.blur_radius[0], rb->ssr.blur_radius[1], p_metallic, p_metallic_mask, rb->depth_texture, rb->ssr.depth_scaled, rb->ssr.normal_scaled, rb->blur[0].mipmaps[1].texture, rb->blur[1].mipmaps[0].texture, Size2i(rb->width / 2, rb->height / 2), env->ssr_max_steps, env->ssr_fade_in, env->ssr_fade_out, env->ssr_depth_tolerance, p_projection);
- storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->texture, rb->blur[0].mipmaps[1].texture);
+ storage->get_effects()->screen_space_reflection(rb->internal_texture, p_normal_buffer, ssr_roughness_quality, rb->ssr.blur_radius[0], rb->ssr.blur_radius[1], p_metallic, p_metallic_mask, rb->depth_texture, rb->ssr.depth_scaled, rb->ssr.normal_scaled, rb->blur[0].mipmaps[1].texture, rb->blur[1].mipmaps[0].texture, Size2i(rb->internal_width / 2, rb->internal_height / 2), env->ssr_max_steps, env->ssr_fade_in, env->ssr_fade_out, env->ssr_depth_tolerance, p_projection);
+ storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->internal_texture, rb->blur[0].mipmaps[1].texture);
}
void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND(!rb);
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_environment);
ERR_FAIL_COND(!env);
RENDER_TIMESTAMP("Process SSAO");
@@ -1620,15 +1944,15 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
int half_width;
int half_height;
if (ssao_half_size) {
- buffer_width = (rb->width + 3) / 4;
- buffer_height = (rb->height + 3) / 4;
- half_width = (rb->width + 7) / 8;
- half_height = (rb->height + 7) / 8;
+ buffer_width = (rb->internal_width + 3) / 4;
+ buffer_height = (rb->internal_height + 3) / 4;
+ half_width = (rb->internal_width + 7) / 8;
+ half_height = (rb->internal_height + 7) / 8;
} else {
- buffer_width = (rb->width + 1) / 2;
- buffer_height = (rb->height + 1) / 2;
- half_width = (rb->width + 3) / 4;
- half_height = (rb->height + 3) / 4;
+ buffer_width = (rb->internal_width + 1) / 2;
+ buffer_height = (rb->internal_height + 1) / 2;
+ half_width = (rb->internal_width + 3) / 4;
+ half_height = (rb->internal_height + 3) / 4;
}
bool uniform_sets_are_invalid = false;
if (rb->ssao.depth.is_null()) {
@@ -1700,8 +2024,8 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
{
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8_UNORM;
- tf.width = rb->width;
- tf.height = rb->height;
+ tf.width = rb->internal_width;
+ tf.height = rb->internal_height;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
rb->ssao.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(rb->ssao.ao_final, "SSAO Final");
@@ -1724,33 +2048,118 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
settings.blur_passes = ssao_blur_passes;
settings.fadeout_from = ssao_fadeout_from;
settings.fadeout_to = ssao_fadeout_to;
- settings.full_screen_size = Size2i(rb->width, rb->height);
+ settings.full_screen_size = Size2i(rb->internal_width, rb->internal_height);
settings.half_screen_size = Size2i(buffer_width, buffer_height);
settings.quarter_screen_size = Size2i(half_width, half_height);
- storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao_deinterleaved, rb->ssao.ao_deinterleaved_slices, rb->ssao.ao_pong, rb->ssao.ao_pong_slices, rb->ssao.ao_final, rb->ssao.importance_map[0], rb->ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid);
+ storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao_deinterleaved, rb->ssao.ao_deinterleaved_slices, rb->ssao.ao_pong, rb->ssao.ao_pong_slices, rb->ssao.ao_final, rb->ssao.importance_map[0], rb->ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid, rb->ssao.downsample_uniform_set, rb->ssao.gather_uniform_set, rb->ssao.importance_map_uniform_set);
+}
+
+void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderDataRD *p_render_data) {
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
+ ERR_FAIL_COND(!rb);
+
+ RD::get_singleton()->draw_command_begin_label("Copy screen texture");
+
+ if (rb->blur[0].texture.is_null()) {
+ _allocate_blur_textures(rb);
+ }
+
+ // @TODO IMPLEMENT MULTIVIEW, all effects need to support stereo buffers or effects are only applied to the left eye
+
+ bool can_use_storage = _render_buffers_can_be_storage();
+
+ if (can_use_storage) {
+ storage->get_effects()->copy_to_rect(rb->texture, rb->blur[0].mipmaps[0].texture, Rect2i(0, 0, rb->width, rb->height));
+ for (int i = 1; i < rb->blur[0].mipmaps.size(); i++) {
+ storage->get_effects()->make_mipmap(rb->blur[0].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i].texture, Size2i(rb->blur[0].mipmaps[i].width, rb->blur[0].mipmaps[i].height));
+ }
+ } else {
+ storage->get_effects()->copy_to_fb_rect(rb->texture, rb->blur[0].mipmaps[0].fb, Rect2i(0, 0, rb->width, rb->height));
+ for (int i = 1; i < rb->blur[0].mipmaps.size(); i++) {
+ storage->get_effects()->make_mipmap_raster(rb->blur[0].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i].fb, Size2i(rb->blur[0].mipmaps[i].width, rb->blur[0].mipmaps[i].height));
+ }
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RendererSceneRenderRD::_render_buffers_copy_depth_texture(const RenderDataRD *p_render_data) {
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
+ ERR_FAIL_COND(!rb);
+
+ RD::get_singleton()->draw_command_begin_label("Copy depth texture");
+
+ if (rb->depth_back_texture.is_null()) {
+ _allocate_depth_backbuffer_textures(rb);
+ }
+
+ // @TODO IMPLEMENT MULTIVIEW, all effects need to support stereo buffers or effects are only applied to the left eye
+
+ bool can_use_storage = _render_buffers_can_be_storage();
+
+ if (can_use_storage) {
+ storage->get_effects()->copy_to_rect(rb->depth_texture, rb->depth_back_texture, Rect2i(0, 0, rb->width, rb->height));
+ } else {
+ storage->get_effects()->copy_to_fb_rect(rb->depth_texture, rb->depth_back_fb, Rect2i(0, 0, rb->width, rb->height));
+ }
+
+ RD::get_singleton()->draw_command_end_label();
}
void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
ERR_FAIL_COND(!rb);
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_render_data->environment);
- //glow (if enabled)
- CameraEffects *camfx = camera_effects_owner.getornull(p_render_data->camera_effects);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_render_data->environment);
+ // Glow and override exposure (if enabled).
+ CameraEffects *camfx = camera_effects_owner.get_or_null(p_render_data->camera_effects);
bool can_use_effects = rb->width >= 8 && rb->height >= 8;
+ bool can_use_storage = _render_buffers_can_be_storage();
+
+ // @TODO IMPLEMENT MULTIVIEW, all effects need to support stereo buffers or effects are only applied to the left eye
if (can_use_effects && camfx && (camfx->dof_blur_near_enabled || camfx->dof_blur_far_enabled) && camfx->dof_blur_amount > 0.0) {
+ RD::get_singleton()->draw_command_begin_label("DOF");
if (rb->blur[0].texture.is_null()) {
_allocate_blur_textures(rb);
}
+ EffectsRD::BokehBuffers buffers;
+
+ // Textures we use
+ buffers.base_texture_size = Size2i(rb->internal_width, rb->internal_height);
+ buffers.base_texture = rb->internal_texture;
+ buffers.depth_texture = rb->depth_texture;
+ buffers.secondary_texture = rb->blur[0].mipmaps[0].texture;
+ buffers.half_texture[0] = rb->blur[1].mipmaps[0].texture;
+ buffers.half_texture[1] = rb->blur[0].mipmaps[1].texture;
+
float bokeh_size = camfx->dof_blur_amount * 64.0;
- storage->get_effects()->bokeh_dof(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->blur[0].mipmaps[0].texture, rb->blur[1].mipmaps[0].texture, rb->blur[0].mipmaps[1].texture, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
+ if (can_use_storage) {
+ storage->get_effects()->bokeh_dof(buffers, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
+ } else {
+ // Set framebuffers.
+ buffers.base_fb = rb->texture_fb;
+ buffers.secondary_fb = rb->weight_buffers[1].fb;
+ buffers.half_fb[0] = rb->weight_buffers[2].fb;
+ buffers.half_fb[1] = rb->weight_buffers[3].fb;
+ buffers.weight_texture[0] = rb->weight_buffers[0].weight;
+ buffers.weight_texture[1] = rb->weight_buffers[1].weight;
+ buffers.weight_texture[2] = rb->weight_buffers[2].weight;
+ buffers.weight_texture[3] = rb->weight_buffers[3].weight;
+
+ // Set weight buffers.
+ buffers.base_weight_fb = rb->base_weight_fb;
+
+ storage->get_effects()->bokeh_dof_raster(buffers, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
+ }
+ RD::get_singleton()->draw_command_end_label();
}
if (can_use_effects && env && env->auto_exposure) {
+ RD::get_singleton()->draw_command_begin_label("Auto exposure");
if (rb->luminance.current.is_null()) {
_allocate_luminance_textures(rb);
}
@@ -1759,16 +2168,26 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
rb->auto_exposure_version = env->auto_exposure_version;
double step = env->auto_exp_speed * time_step;
- storage->get_effects()->luminance_reduction(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate);
-
- //swap final reduce with prev luminance
+ if (can_use_storage) {
+ storage->get_effects()->luminance_reduction(rb->internal_texture, Size2i(rb->internal_width, rb->internal_height), rb->luminance.reduce, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate);
+ } else {
+ storage->get_effects()->luminance_reduction_raster(rb->internal_texture, Size2i(rb->internal_width, rb->internal_height), rb->luminance.reduce, rb->luminance.fb, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate);
+ }
+ // Swap final reduce with prev luminance.
SWAP(rb->luminance.current, rb->luminance.reduce.write[rb->luminance.reduce.size() - 1]);
- RenderingServerDefault::redraw_request(); //redraw all the time if auto exposure rendering is on
+ if (!can_use_storage) {
+ SWAP(rb->luminance.current_fb, rb->luminance.fb.write[rb->luminance.fb.size() - 1]);
+ }
+
+ RenderingServerDefault::redraw_request(); // Redraw all the time if auto exposure rendering is on.
+ RD::get_singleton()->draw_command_end_label();
}
int max_glow_level = -1;
if (can_use_effects && env && env->glow_enabled) {
+ RD::get_singleton()->draw_command_begin_label("Gaussian Glow");
+
/* see that blur textures are allocated */
if (rb->blur[1].texture.is_null()) {
@@ -1794,15 +2213,26 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
if (env->auto_exposure && rb->luminance.current.is_valid()) {
luminance_texture = rb->luminance.current;
}
- storage->get_effects()->gaussian_glow(rb->texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, 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);
+ if (can_use_storage) {
+ storage->get_effects()->gaussian_glow(rb->internal_texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, 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_raster(rb->internal_texture, rb->blur[1].mipmaps[i].half_fb, rb->blur[1].mipmaps[i].half_texture, rb->blur[1].mipmaps[i].fb, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, 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[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality);
+ if (can_use_storage) {
+ storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality);
+ } else {
+ storage->get_effects()->gaussian_glow_raster(rb->blur[1].mipmaps[i - 1].texture, rb->blur[1].mipmaps[i].half_fb, rb->blur[1].mipmaps[i].half_texture, rb->blur[1].mipmaps[i].fb, Vector2(1.0 / vp_w, 1.0 / vp_h), env->glow_strength, glow_high_quality);
+ }
}
}
+
+ RD::get_singleton()->draw_command_end_label();
}
{
- //tonemap
+ RD::get_singleton()->draw_command_begin_label("Tonemap");
+
EffectsRD::TonemapSettings tonemap;
if (can_use_effects && env && env->auto_exposure && rb->luminance.current.is_valid()) {
@@ -1833,7 +2263,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
}
tonemap.use_debanding = rb->use_debanding;
- tonemap.texture_size = Vector2i(rb->width, rb->height);
+ tonemap.texture_size = Vector2i(rb->internal_width, rb->internal_height);
if (env) {
tonemap.tonemap_mode = env->tone_mapper;
@@ -1841,6 +2271,10 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
tonemap.exposure = env->exposure;
}
+ if (camfx && camfx->override_exposure_enabled) {
+ tonemap.exposure = camfx->override_exposure;
+ }
+
tonemap.use_color_correction = false;
tonemap.use_1d_color_correction = false;
tonemap.color_correction_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
@@ -1857,16 +2291,104 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
}
}
- storage->get_effects()->tonemapper(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap);
+ tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier();
+ tonemap.view_count = p_render_data->view_count;
+
+ storage->get_effects()->tonemapper(rb->internal_texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap);
+
+ RD::get_singleton()->draw_command_end_label();
+ }
+
+ if (can_use_effects && can_use_storage && (rb->internal_width != rb->width || rb->internal_height != rb->height)) {
+ RD::get_singleton()->draw_command_begin_label("FSR Upscale");
+
+ storage->get_effects()->fsr_upscale(rb->internal_texture, rb->upscale_texture, rb->texture, Size2i(rb->internal_width, rb->internal_height), Size2i(rb->width, rb->height), rb->fsr_sharpness);
+
+ RD::get_singleton()->draw_command_end_label();
}
storage->render_target_disable_clear_request(rb->render_target);
}
+void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data) {
+ RD::get_singleton()->draw_command_begin_label("Post Process Subpass");
+
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
+ ERR_FAIL_COND(!rb);
+
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_render_data->environment);
+ // Override exposure (if enabled).
+ CameraEffects *camfx = camera_effects_owner.get_or_null(p_render_data->camera_effects);
+
+ bool can_use_effects = rb->width >= 8 && rb->height >= 8;
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
+
+ EffectsRD::TonemapSettings tonemap;
+
+ if (env) {
+ tonemap.tonemap_mode = env->tone_mapper;
+ tonemap.exposure = env->exposure;
+ tonemap.white = env->white;
+ }
+
+ if (camfx && camfx->override_exposure_enabled) {
+ tonemap.exposure = camfx->override_exposure;
+ }
+
+ // We don't support glow or auto exposure here, if they are needed, don't use subpasses!
+ // The problem is that we need to use the result so far and process them before we can
+ // apply this to our results.
+ if (can_use_effects && env && env->glow_enabled) {
+ ERR_FAIL_MSG("Glow is not supported when using subpasses.");
+ }
+ if (can_use_effects && env && env->auto_exposure) {
+ ERR_FAIL_MSG("Glow is not supported when using subpasses.");
+ }
+
+ tonemap.use_glow = false;
+ tonemap.glow_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
+ tonemap.use_auto_exposure = false;
+ tonemap.exposure_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+
+ tonemap.use_color_correction = false;
+ tonemap.use_1d_color_correction = false;
+ tonemap.color_correction_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+
+ if (can_use_effects && env) {
+ tonemap.use_bcs = env->adjustments_enabled;
+ tonemap.brightness = env->adjustments_brightness;
+ tonemap.contrast = env->adjustments_contrast;
+ tonemap.saturation = env->adjustments_saturation;
+ if (env->adjustments_enabled && env->color_correction.is_valid()) {
+ tonemap.use_color_correction = true;
+ tonemap.use_1d_color_correction = env->use_1d_color_correction;
+ tonemap.color_correction_texture = storage->texture_get_rd_texture(env->color_correction);
+ }
+ }
+
+ tonemap.use_debanding = rb->use_debanding;
+ tonemap.texture_size = Vector2i(rb->width, rb->height);
+
+ tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier();
+ tonemap.view_count = p_render_data->view_count;
+
+ storage->get_effects()->tonemapper(draw_list, p_source_texture, RD::get_singleton()->framebuffer_get_format(p_framebuffer), tonemap);
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RendererSceneRenderRD::_disable_clear_request(const RenderDataRD *p_render_data) {
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
+ ERR_FAIL_COND(!rb);
+
+ storage->render_target_disable_clear_request(rb->render_target);
+}
+
void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) {
EffectsRD *effects = storage->get_effects();
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND(!rb);
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS) {
@@ -1932,7 +2454,7 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID
}
void RendererSceneRenderRD::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) {
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->adjustments_enabled = p_enable;
@@ -1944,7 +2466,7 @@ void RendererSceneRenderRD::environment_set_adjustment(RID p_env, bool p_enable,
}
RID RendererSceneRenderRD::render_buffers_get_back_buffer_texture(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, RID());
if (!rb->blur[0].texture.is_valid()) {
return RID(); //not valid at the moment
@@ -1952,52 +2474,68 @@ RID RendererSceneRenderRD::render_buffers_get_back_buffer_texture(RID p_render_b
return rb->blur[0].texture;
}
+RID RendererSceneRenderRD::render_buffers_get_back_depth_texture(RID p_render_buffers) {
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
+ ERR_FAIL_COND_V(!rb, RID());
+ if (!rb->depth_back_texture.is_valid()) {
+ return RID(); //not valid at the moment
+ }
+ return rb->depth_back_texture;
+}
+
+RID RendererSceneRenderRD::render_buffers_get_depth_texture(RID p_render_buffers) {
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
+ ERR_FAIL_COND_V(!rb, RID());
+
+ return rb->depth_texture;
+}
+
RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, RID());
return rb->ssao.ao_final;
}
-RID RendererSceneRenderRD::render_buffers_get_gi_probe_buffer(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+RID RendererSceneRenderRD::render_buffers_get_voxel_gi_buffer(RID p_render_buffers) {
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, RID());
- if (rb->gi.giprobe_buffer.is_null()) {
- rb->gi.giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(RendererSceneGIRD::GIProbeData) * RendererSceneGIRD::MAX_GIPROBES);
+ if (rb->gi.voxel_gi_buffer.is_null()) {
+ rb->gi.voxel_gi_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(RendererSceneGIRD::VoxelGIData) * RendererSceneGIRD::MAX_VOXEL_GI_INSTANCES);
}
- return rb->gi.giprobe_buffer;
+ return rb->gi.voxel_gi_buffer;
}
-RID RendererSceneRenderRD::render_buffers_get_default_gi_probe_buffer() {
- return gi.default_giprobe_buffer;
+RID RendererSceneRenderRD::render_buffers_get_default_voxel_gi_buffer() {
+ return gi.default_voxel_gi_buffer;
}
RID RendererSceneRenderRD::render_buffers_get_gi_ambient_texture(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, RID());
return rb->ambient_buffer;
}
RID RendererSceneRenderRD::render_buffers_get_gi_reflection_texture(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, RID());
return rb->reflection_buffer;
}
uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_count(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, 0);
ERR_FAIL_COND_V(!rb->sdfgi, 0);
return rb->sdfgi->cascades.size();
}
bool RendererSceneRenderRD::render_buffers_is_sdfgi_enabled(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, false);
return rb->sdfgi != nullptr;
}
RID RendererSceneRenderRD::render_buffers_get_sdfgi_irradiance_probes(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, RID());
ERR_FAIL_COND_V(!rb->sdfgi, RID());
@@ -2005,7 +2543,7 @@ RID RendererSceneRenderRD::render_buffers_get_sdfgi_irradiance_probes(RID p_rend
}
Vector3 RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_offset(RID p_render_buffers, uint32_t p_cascade) const {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, Vector3());
ERR_FAIL_COND_V(!rb->sdfgi, Vector3());
ERR_FAIL_UNSIGNED_INDEX_V(p_cascade, rb->sdfgi->cascades.size(), Vector3());
@@ -2014,7 +2552,7 @@ Vector3 RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_offset(RID p_ren
}
Vector3i RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_offset(RID p_render_buffers, uint32_t p_cascade) const {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, Vector3i());
ERR_FAIL_COND_V(!rb->sdfgi, Vector3i());
ERR_FAIL_UNSIGNED_INDEX_V(p_cascade, rb->sdfgi->cascades.size(), Vector3i());
@@ -2024,14 +2562,14 @@ Vector3i RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_offset(RI
}
float RendererSceneRenderRD::render_buffers_get_sdfgi_normal_bias(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, 0);
ERR_FAIL_COND_V(!rb->sdfgi, 0);
return rb->sdfgi->normal_bias;
}
float RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_size(RID p_render_buffers, uint32_t p_cascade) const {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, 0);
ERR_FAIL_COND_V(!rb->sdfgi, 0);
ERR_FAIL_UNSIGNED_INDEX_V(p_cascade, rb->sdfgi->cascades.size(), 0);
@@ -2039,7 +2577,7 @@ float RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_size(RID p_r
return float(rb->sdfgi->cascade_size) * rb->sdfgi->cascades[p_cascade].cell_size / float(rb->sdfgi->probe_axis_count - 1);
}
uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_count(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, 0);
ERR_FAIL_COND_V(!rb->sdfgi, 0);
@@ -2047,7 +2585,7 @@ uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_count(RID
}
uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_size(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, 0);
ERR_FAIL_COND_V(!rb->sdfgi, 0);
@@ -2055,7 +2593,7 @@ uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_size(RID p_rend
}
bool RendererSceneRenderRD::render_buffers_is_sdfgi_using_occlusion(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, false);
ERR_FAIL_COND_V(!rb->sdfgi, false);
@@ -2063,14 +2601,14 @@ bool RendererSceneRenderRD::render_buffers_is_sdfgi_using_occlusion(RID p_render
}
float RendererSceneRenderRD::render_buffers_get_sdfgi_energy(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, 0.0);
ERR_FAIL_COND_V(!rb->sdfgi, 0.0);
return rb->sdfgi->energy;
}
RID RendererSceneRenderRD::render_buffers_get_sdfgi_occlusion_texture(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, RID());
ERR_FAIL_COND_V(!rb->sdfgi, RID());
@@ -2078,20 +2616,20 @@ RID RendererSceneRenderRD::render_buffers_get_sdfgi_occlusion_texture(RID p_rend
}
bool RendererSceneRenderRD::render_buffers_has_volumetric_fog(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, false);
return rb->volumetric_fog != nullptr;
}
RID RendererSceneRenderRD::render_buffers_get_volumetric_fog_texture(RID p_render_buffers) {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, RID());
return rb->volumetric_fog->fog_map;
}
RID RendererSceneRenderRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers) {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, RID());
if (!rb->volumetric_fog) {
@@ -2102,24 +2640,55 @@ RID RendererSceneRenderRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID
}
float RendererSceneRenderRD::render_buffers_get_volumetric_fog_end(RID p_render_buffers) {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0);
return rb->volumetric_fog->length;
}
float RendererSceneRenderRD::render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers) {
- const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0);
return rb->volumetric_fog->spread;
}
-void RendererSceneRenderRD::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, bool p_use_debanding) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+float RendererSceneRenderRD::_render_buffers_get_luminance_multiplier() {
+ return 1.0;
+}
+
+RD::DataFormat RendererSceneRenderRD::_render_buffers_get_color_format() {
+ return RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+}
+
+bool RendererSceneRenderRD::_render_buffers_can_be_storage() {
+ return true;
+}
+
+void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) {
+ ERR_FAIL_COND_MSG(p_view_count == 0, "Must have at least 1 view");
+
+ if (!_render_buffers_can_be_storage()) {
+ p_internal_height = p_height;
+ p_internal_width = p_width;
+ }
+
+ if (p_width != p_internal_width) {
+ float fsr_mipmap_bias = -log2f(p_width / p_internal_width) + p_fsr_mipmap_bias;
+ storage->sampler_rd_configure_custom(fsr_mipmap_bias);
+ update_uniform_sets();
+ }
+
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
+
+ // Should we add an overrule per viewport?
+ rb->internal_width = p_internal_width;
+ rb->internal_height = p_internal_height;
rb->width = p_width;
rb->height = p_height;
+ rb->fsr_sharpness = p_fsr_sharpness;
rb->render_target = p_render_target;
rb->msaa = p_msaa;
rb->screen_space_aa = p_screen_space_aa;
rb->use_debanding = p_use_debanding;
+ rb->view_count = p_view_count;
if (is_clustered_enabled()) {
if (rb->cluster_builder == nullptr) {
@@ -2132,30 +2701,47 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
{
RD::TextureFormat tf;
- 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;
+ if (rb->view_count > 1) {
+ tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ }
+ tf.format = _render_buffers_get_color_format();
+ tf.width = rb->internal_width; // If set to rb->width, msaa won't crash
+ tf.height = rb->internal_height; // If set to rb->width, msaa won't crash
+ tf.array_layers = rb->view_count; // create a layer for every view
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0) | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
- tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
- } else {
- tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
}
+ tf.usage_bits |= RD::TEXTURE_USAGE_INPUT_ATTACHMENT_BIT; // only needed when using subpasses in the mobile renderer
+
+ rb->internal_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
- rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ if ((p_internal_width != p_width || p_internal_height != p_height)) {
+ tf.width = rb->width;
+ tf.height = rb->height;
+ rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ rb->upscale_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ } else {
+ rb->texture = rb->internal_texture;
+ rb->upscale_texture = rb->internal_texture;
+ }
}
{
RD::TextureFormat tf;
+ if (rb->view_count > 1) {
+ tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ }
if (rb->msaa == RS::VIEWPORT_MSAA_DISABLED) {
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;
} else {
tf.format = RD::DATA_FORMAT_R32_SFLOAT;
}
- tf.width = p_width;
- tf.height = p_height;
+ tf.width = rb->internal_width;
+ tf.height = rb->internal_height;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
+ tf.array_layers = rb->view_count; // create a layer for every view
if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
@@ -2166,10 +2752,19 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
rb->depth_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
}
- rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa);
+ if (!_render_buffers_can_be_storage()) {
+ // ONLY USED ON MOBILE RENDERER, ONLY USED FOR POST EFFECTS!
+ Vector<RID> fb;
+ fb.push_back(rb->internal_texture);
+
+ rb->texture_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, rb->view_count);
+ }
+
+ RID target_texture = storage->render_target_get_rd_texture(rb->render_target);
+ rb->data->configure(rb->internal_texture, rb->depth_texture, target_texture, p_internal_width, p_internal_height, p_msaa, p_view_count);
if (is_clustered_enabled()) {
- rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture);
+ rb->cluster_builder->setup(Size2i(p_internal_width, p_internal_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->internal_texture);
}
}
@@ -2199,9 +2794,14 @@ void RendererSceneRenderRD::shadows_quality_set(RS::ShadowQuality p_quality) {
switch (shadows_quality) {
case RS::SHADOW_QUALITY_HARD: {
penumbra_shadow_samples = 4;
- soft_shadow_samples = 1;
+ soft_shadow_samples = 0;
shadows_quality_radius = 1.0;
} break;
+ case RS::SHADOW_QUALITY_SOFT_VERY_LOW: {
+ penumbra_shadow_samples = 4;
+ soft_shadow_samples = 1;
+ shadows_quality_radius = 1.5;
+ } break;
case RS::SHADOW_QUALITY_SOFT_LOW: {
penumbra_shadow_samples = 8;
soft_shadow_samples = 4;
@@ -2228,6 +2828,8 @@ void RendererSceneRenderRD::shadows_quality_set(RS::ShadowQuality p_quality) {
get_vogel_disk(penumbra_shadow_kernel, penumbra_shadow_samples);
get_vogel_disk(soft_shadow_kernel, soft_shadow_samples);
}
+
+ _update_shader_quality_settings();
}
void RendererSceneRenderRD::directional_shadow_quality_set(RS::ShadowQuality p_quality) {
@@ -2239,9 +2841,14 @@ void RendererSceneRenderRD::directional_shadow_quality_set(RS::ShadowQuality p_q
switch (directional_shadow_quality) {
case RS::SHADOW_QUALITY_HARD: {
directional_penumbra_shadow_samples = 4;
- directional_soft_shadow_samples = 1;
+ directional_soft_shadow_samples = 0;
directional_shadow_quality_radius = 1.0;
} break;
+ case RS::SHADOW_QUALITY_SOFT_VERY_LOW: {
+ directional_penumbra_shadow_samples = 4;
+ directional_soft_shadow_samples = 1;
+ directional_shadow_quality_radius = 1.5;
+ } break;
case RS::SHADOW_QUALITY_SOFT_LOW: {
directional_penumbra_shadow_samples = 8;
directional_soft_shadow_samples = 4;
@@ -2268,6 +2875,23 @@ void RendererSceneRenderRD::directional_shadow_quality_set(RS::ShadowQuality p_q
get_vogel_disk(directional_penumbra_shadow_kernel, directional_penumbra_shadow_samples);
get_vogel_disk(directional_soft_shadow_kernel, directional_soft_shadow_samples);
}
+
+ _update_shader_quality_settings();
+}
+
+void RendererSceneRenderRD::decals_set_filter(RenderingServer::DecalFilter p_filter) {
+ if (decals_filter == p_filter) {
+ return;
+ }
+ decals_filter = p_filter;
+ _update_shader_quality_settings();
+}
+void RendererSceneRenderRD::light_projectors_set_filter(RenderingServer::LightProjectorFilter p_filter) {
+ if (light_projectors_filter == p_filter) {
+ return;
+ }
+ light_projectors_filter = p_filter;
+ _update_shader_quality_settings();
}
int RendererSceneRenderRD::get_roughness_layers() const {
@@ -2279,12 +2903,12 @@ bool RendererSceneRenderRD::is_using_radiance_cubemap_array() const {
}
RendererSceneRenderRD::RenderBufferData *RendererSceneRenderRD::render_buffers_get_data(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND_V(!rb, nullptr);
return rb->data;
}
-void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment) {
+void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment) {
cluster.reflection_count = 0;
for (uint32_t i = 0; i < (uint32_t)p_reflections.size(); i++) {
@@ -2292,7 +2916,7 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
break;
}
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflections[i]);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_reflections[i]);
if (!rpi) {
continue;
}
@@ -2307,10 +2931,13 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
sort_array.sort(cluster.reflection_sort, cluster.reflection_count);
}
+ bool using_forward_ids = _uses_forward_ids();
for (uint32_t i = 0; i < cluster.reflection_count; i++) {
ReflectionProbeInstance *rpi = cluster.reflection_sort[i].instance;
- rpi->render_index = i;
+ if (using_forward_ids) {
+ _map_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id, i);
+ }
RID base_probe = rpi->probe;
@@ -2344,8 +2971,8 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
reflection_ubo.ambient[1] = ambient_linear.g * interior_ambient_energy;
reflection_ubo.ambient[2] = ambient_linear.b * interior_ambient_energy;
- Transform transform = rpi->transform;
- Transform proj = (p_camera_inverse_transform * transform).inverse();
+ Transform3D transform = rpi->transform;
+ Transform3D proj = (p_camera_inverse_transform * transform).inverse();
RendererStorageRD::store_transform(proj, reflection_ubo.local_matrix);
if (current_cluster_builder != nullptr) {
@@ -2360,20 +2987,22 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
}
}
-void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const Transform &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) {
- Transform inverse_transform = p_camera_transform.affine_inverse();
+void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows) {
+ Transform3D inverse_transform = p_camera_transform.affine_inverse();
r_directional_light_count = 0;
r_positional_light_count = 0;
sky.sky_scene_state.ubo.directional_light_count = 0;
- Plane camera_plane(p_camera_transform.origin, -p_camera_transform.basis.get_axis(Vector3::AXIS_Z).normalized());
+ Plane camera_plane(-p_camera_transform.basis.get_axis(Vector3::AXIS_Z).normalized(), p_camera_transform.origin);
cluster.omni_light_count = 0;
cluster.spot_light_count = 0;
+ r_directional_light_soft_shadows = false;
+
for (int i = 0; i < (int)p_lights.size(); i++) {
- LightInstance *li = light_instance_owner.getornull(p_lights[i]);
+ LightInstance *li = light_instance_owner.get_or_null(p_lights[i]);
if (!li) {
continue;
}
@@ -2387,7 +3016,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
// Copy to SkyDirectionalLightData
if (r_directional_light_count < sky.sky_scene_state.max_directional_lights) {
RendererSceneSkyRD::SkyDirectionalLightData &sky_light_data = sky.sky_scene_state.directional_lights[r_directional_light_count];
- Transform light_transform = li->transform;
+ Transform3D light_transform = li->transform;
Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
sky_light_data.direction[0] = world_direction.x;
@@ -2410,6 +3039,9 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
// 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)
angular_diameter = Math::tan(Math::deg2rad(angular_diameter));
+ if (storage->light_has_shadow(base)) {
+ r_directional_light_soft_shadows = true;
+ }
} else {
angular_diameter = 0.0;
}
@@ -2423,7 +3055,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
Cluster::DirectionalLightData &light_data = cluster.directional_lights[r_directional_light_count];
- Transform light_transform = li->transform;
+ Transform3D light_transform = li->transform;
Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized();
@@ -2502,7 +3134,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
RS::LightDirectionalShadowMode smode = storage->light_directional_get_shadow_mode(base);
int limit = smode == RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3);
- light_data.blend_splits = storage->light_directional_get_blend_splits(base);
+ light_data.blend_splits = (smode != RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL) && storage->light_directional_get_blend_splits(base);
for (int j = 0; j < 4; j++) {
Rect2 atlas_rect = li->shadow_transform[j].atlas_rect;
CameraMatrix matrix = li->shadow_transform[j].camera;
@@ -2513,12 +3145,12 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
CameraMatrix rectm;
rectm.set_light_atlas_rect(atlas_rect);
- Transform modelview = (inverse_transform * li->shadow_transform[j].transform).inverse();
+ Transform3D modelview = (inverse_transform * li->shadow_transform[j].transform).inverse();
CameraMatrix shadow_mtx = rectm * bias * matrix * modelview;
light_data.shadow_split_offsets[j] = split;
float bias_scale = li->shadow_transform[j].bias_scale;
- light_data.shadow_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * bias_scale;
+ light_data.shadow_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) / 100.0 * bias_scale;
light_data.shadow_normal_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * li->shadow_transform[j].shadow_texel_size;
light_data.shadow_transmittance_bias[j] = storage->light_get_transmittance_bias(base) * bias_scale;
light_data.shadow_z_range[j] = li->shadow_transform[j].farplane;
@@ -2599,9 +3231,11 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
ShadowAtlas *shadow_atlas = nullptr;
if (p_shadow_atlas.is_valid() && p_using_shadows) {
- shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
+ shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
}
+ bool using_forward_ids = _uses_forward_ids();
+
for (uint32_t i = 0; i < (cluster.omni_light_count + cluster.spot_light_count); i++) {
uint32_t index = (i < cluster.omni_light_count) ? i : i - (cluster.omni_light_count);
Cluster::LightData &light_data = (i < cluster.omni_light_count) ? cluster.omni_lights[index] : cluster.spot_lights[index];
@@ -2609,7 +3243,11 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
LightInstance *li = (i < cluster.omni_light_count) ? cluster.omni_light_sort[index].instance : cluster.spot_light_sort[index].instance;
RID base = li->light;
- Transform light_transform = li->transform;
+ if (using_forward_ids) {
+ _map_forward_id(type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT, li->forward_id, index);
+ }
+
+ Transform3D light_transform = li->transform;
float sign = storage->light_is_negative(base) ? -1 : 1;
Color linear_col = storage->light_get_color(base).to_linear();
@@ -2682,22 +3320,19 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.shadow_enabled = true;
- if (type == RS::LIGHT_SPOT) {
- light_data.shadow_bias = (storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0);
- float shadow_texel_size = Math::tan(Math::deg2rad(spot_angle)) * radius * 2.0;
- shadow_texel_size *= light_instance_get_shadow_texel_size(li->self, p_shadow_atlas);
-
- light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size;
+ float shadow_texel_size = light_instance_get_shadow_texel_size(li->self, p_shadow_atlas);
+ light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 10.0;
+ if (type == RS::LIGHT_SPOT) {
+ light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) / 100.0;
} 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->self, p_shadow_atlas);
- light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 2.0; // applied in -1 .. 1 space
+ light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS);
}
light_data.transmittance_bias = storage->light_get_transmittance_bias(base);
- Rect2 rect = light_instance_get_shadow_atlas_rect(li->self, p_shadow_atlas);
+ Vector2i omni_offset;
+ Rect2 rect = light_instance_get_shadow_atlas_rect(li->self, p_shadow_atlas, omni_offset);
light_data.atlas_rect[0] = rect.position.x;
light_data.atlas_rect[1] = rect.position.y;
@@ -2708,8 +3343,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.shadow_volumetric_fog_fade = 1.0 / storage->light_get_shadow_volumetric_fog_fade(base);
if (type == RS::LIGHT_OMNI) {
- light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another
- Transform proj = (inverse_transform * light_transform).inverse();
+ Transform3D proj = (inverse_transform * light_transform).inverse();
RendererStorageRD::store_transform(proj, light_data.shadow_matrix);
@@ -2720,8 +3354,10 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF
}
+ light_data.direction[0] = omni_offset.x * float(rect.size.width);
+ light_data.direction[1] = omni_offset.y * float(rect.size.height);
} else if (type == RS::LIGHT_SPOT) {
- Transform modelview = (inverse_transform * light_transform).inverse();
+ Transform3D modelview = (inverse_transform * light_transform).inverse();
CameraMatrix bias;
bias.set_light_bias();
@@ -2741,7 +3377,6 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.shadow_enabled = false;
}
- li->light_index = index;
li->cull_mask = storage->light_get_cull_mask(base);
if (current_cluster_builder != nullptr) {
@@ -2765,8 +3400,8 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
}
}
-void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform) {
- Transform uv_xform;
+void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform) {
+ Transform3D uv_xform;
uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0));
uv_xform.origin = Vector3(-1.0, 0.0, -1.0);
@@ -2779,13 +3414,13 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
break;
}
- DecalInstance *di = decal_instance_owner.getornull(p_decals[i]);
+ DecalInstance *di = decal_instance_owner.get_or_null(p_decals[i]);
if (!di) {
continue;
}
RID decal = di->decal;
- Transform xform = di->transform;
+ Transform3D xform = di->transform;
real_t distance = -p_camera_inverse_xform.xform(xform.origin).z;
@@ -2810,14 +3445,18 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
sort_array.sort(cluster.decal_sort, cluster.decal_count);
}
+ bool using_forward_ids = _uses_forward_ids();
for (uint32_t i = 0; i < cluster.decal_count; i++) {
DecalInstance *di = cluster.decal_sort[i].instance;
RID decal = di->decal;
- di->render_index = i;
+ if (using_forward_ids) {
+ _map_forward_id(FORWARD_ID_TYPE_DECAL, di->forward_id, i);
+ }
+
di->cull_mask = storage->decal_get_cull_mask(decal);
- Transform xform = di->transform;
+ Transform3D xform = di->transform;
float fade = 1.0;
if (storage->decal_is_distance_fade_enabled(decal)) {
@@ -2834,9 +3473,9 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
Vector3 decal_extents = storage->decal_get_extents(decal);
- Transform scale_xform;
- scale_xform.basis.scale(Vector3(decal_extents.x, decal_extents.y, decal_extents.z));
- Transform to_decal_xform = (p_camera_inverse_xform * di->transform * scale_xform * uv_xform).affine_inverse();
+ Transform3D scale_xform;
+ scale_xform.basis.scale(decal_extents);
+ Transform3D to_decal_xform = (p_camera_inverse_xform * di->transform * scale_xform * uv_xform).affine_inverse();
RendererStorageRD::store_transform(to_decal_xform, dd.xform);
Vector3 normal = xform.basis.get_axis(Vector3::AXIS_Y).normalized();
@@ -2931,116 +3570,189 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
}
}
-void RendererSceneRenderRD::_fill_instance_indices(const RID *p_omni_light_instances, uint32_t p_omni_light_instance_count, uint32_t *p_omni_light_indices, const RID *p_spot_light_instances, uint32_t p_spot_light_instance_count, uint32_t *p_spot_light_indices, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count, uint32_t *p_reflection_probe_indices, const RID *p_decal_instances, uint32_t p_decal_instance_count, uint32_t *p_decal_instance_indices, uint32_t p_layer_mask, uint32_t p_max_dst_words) {
- // first zero out our indices
- for (uint32_t i = 0; i < p_max_dst_words; i++) {
- p_omni_light_indices[i] = 0;
- p_spot_light_indices[i] = 0;
- p_reflection_probe_indices[i] = 0;
- p_decal_instance_indices[i] = 0;
+////////////////////////////////////////////////////////////////////////////////
+// FOG SHADER
+
+void RendererSceneRenderRD::FogShaderData::set_code(const String &p_code) {
+ //compile
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+
+ if (code == String()) {
+ return; //just invalid, but no error
}
- {
- // process omni lights
- uint32_t dword = 0;
- uint32_t shift = 0;
-
- for (uint32_t i = 0; i < p_omni_light_instance_count && dword < p_max_dst_words; i++) {
- LightInstance *li = light_instance_owner.getornull(p_omni_light_instances[i]);
-
- if ((li->cull_mask & p_layer_mask) && (li->light_index < 255)) {
- p_omni_light_indices[dword] += li->light_index << shift;
- if (shift == 24) {
- dword++;
- shift = 0;
- } else {
- shift += 8;
- }
- }
- }
+ ShaderCompilerRD::GeneratedCode gen_code;
+ ShaderCompilerRD::IdentifierActions actions;
+ actions.entry_point_stages["fog"] = ShaderCompilerRD::STAGE_COMPUTE;
- if (dword < 2) {
- // put in ending mark
- p_omni_light_indices[dword] += 0xFF << shift;
- }
+ uses_time = false;
+
+ actions.usage_flag_pointers["TIME"] = &uses_time;
+
+ actions.uniforms = &uniforms;
+
+ RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
+
+ Error err = scene_singleton->volumetric_fog.compiler.compile(RS::SHADER_FOG, code, &actions, path, gen_code);
+ ERR_FAIL_COND_MSG(err != OK, "Fog shader compilation failed.");
+
+ if (version.is_null()) {
+ version = scene_singleton->volumetric_fog.shader.version_create();
}
- {
- // process spot lights
- uint32_t dword = 0;
- uint32_t shift = 0;
-
- for (uint32_t i = 0; i < p_spot_light_instance_count && dword < p_max_dst_words; i++) {
- LightInstance *li = light_instance_owner.getornull(p_spot_light_instances[i]);
-
- if ((li->cull_mask & p_layer_mask) && (li->light_index < 255)) {
- p_spot_light_indices[dword] += li->light_index << shift;
- if (shift == 24) {
- dword++;
- shift = 0;
- } else {
- shift += 8;
- }
+ scene_singleton->volumetric_fog.shader.version_set_compute_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_COMPUTE], gen_code.defines);
+ ERR_FAIL_COND(!scene_singleton->volumetric_fog.shader.version_is_valid(version));
+
+ ubo_size = gen_code.uniform_total_size;
+ ubo_offsets = gen_code.uniform_offsets;
+ texture_uniforms = gen_code.texture_uniforms;
+
+ pipeline = RD::get_singleton()->compute_pipeline_create(scene_singleton->volumetric_fog.shader.version_get_shader(version, 0));
+
+ valid = true;
+}
+
+void RendererSceneRenderRD::FogShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+ if (!p_texture.is_valid()) {
+ if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
+ default_texture_params[p_name].erase(p_index);
+
+ if (default_texture_params[p_name].is_empty()) {
+ default_texture_params.erase(p_name);
}
}
-
- if (dword < 2) {
- // put in ending mark
- p_spot_light_indices[dword] += 0xFF << shift;
+ } else {
+ if (!default_texture_params.has(p_name)) {
+ default_texture_params[p_name] = Map<int, RID>();
}
+ default_texture_params[p_name][p_index] = p_texture;
}
+}
- {
- // process reflection probes
- uint32_t dword = 0;
- uint32_t shift = 0;
-
- for (uint32_t i = 0; i < p_reflection_probe_instance_count && dword < p_max_dst_words; i++) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflection_probe_instances[i]);
-
- if ((rpi->cull_mask & p_layer_mask) && (rpi->render_index < 255)) {
- p_reflection_probe_indices[dword] += rpi->render_index << shift;
- if (shift == 24) {
- dword++;
- shift = 0;
- } else {
- shift += 8;
- }
- }
+void RendererSceneRenderRD::FogShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+ Map<int, StringName> order;
+
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
}
- if (dword < 2) {
- // put in ending mark
- p_reflection_probe_indices[dword] += 0xFF << shift;
+ if (E->get().texture_order >= 0) {
+ order[E->get().texture_order + 100000] = E->key();
+ } else {
+ order[E->get().order] = E->key();
}
}
- {
- // process decals
- uint32_t dword = 0;
- uint32_t shift = 0;
-
- for (uint32_t i = 0; i < p_decal_instance_count && dword < p_max_dst_words; i++) {
- DecalInstance *decal = decal_instance_owner.getornull(p_decal_instances[i]);
-
- if ((decal->cull_mask & p_layer_mask) && (decal->render_index < 255)) {
- p_decal_instance_indices[dword] += decal->render_index << shift;
- if (shift == 24) {
- dword++;
- shift = 0;
- } else {
- shift += 8;
- }
- }
- }
+ for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
+ pi.name = E->get();
+ p_param_list->push_back(pi);
+ }
+}
- if (dword < 2) {
- // put in ending mark
- p_decal_instance_indices[dword] += 0xFF << shift;
+void RendererSceneRenderRD::FogShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
}
+
+ RendererStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E->get());
+ p.info.name = E->key(); //supply name
+ p.index = E->get().instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().array_size, E->get().hint);
+ p_param_list->push_back(p);
+ }
+}
+
+bool RendererSceneRenderRD::FogShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
}
+
+ return uniforms[p_param].texture_order >= 0;
}
+bool RendererSceneRenderRD::FogShaderData::is_animated() const {
+ return false;
+}
+
+bool RendererSceneRenderRD::FogShaderData::casts_shadows() const {
+ return false;
+}
+
+Variant RendererSceneRenderRD::FogShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
+ }
+ return Variant();
+}
+
+RS::ShaderNativeSourceCode RendererSceneRenderRD::FogShaderData::get_native_source_code() const {
+ RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
+
+ return scene_singleton->volumetric_fog.shader.version_get_native_source_code(version);
+}
+
+RendererSceneRenderRD::FogShaderData::FogShaderData() {
+ valid = false;
+}
+
+RendererSceneRenderRD::FogShaderData::~FogShaderData() {
+ RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
+ ERR_FAIL_COND(!scene_singleton);
+ //pipeline variants will clear themselves if shader is gone
+ if (version.is_valid()) {
+ scene_singleton->volumetric_fog.shader.version_free(version);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Fog material
+
+bool RendererSceneRenderRD::FogMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
+
+ uniform_set_updated = true;
+
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->volumetric_fog.shader.version_get_shader(shader_data->version, 0), VolumetricFogShader::FogSet::FOG_SET_MATERIAL);
+}
+
+RendererSceneRenderRD::FogMaterialData::~FogMaterialData() {
+ free_parameters_uniform_set(uniform_set);
+}
+
+RendererStorageRD::ShaderData *RendererSceneRenderRD::_create_fog_shader_func() {
+ FogShaderData *shader_data = memnew(FogShaderData);
+ return shader_data;
+}
+
+RendererStorageRD::ShaderData *RendererSceneRenderRD::_create_fog_shader_funcs() {
+ return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->_create_fog_shader_func();
+};
+
+RendererStorageRD::MaterialData *RendererSceneRenderRD::_create_fog_material_func(FogShaderData *p_shader) {
+ FogMaterialData *material_data = memnew(FogMaterialData);
+ material_data->shader_data = p_shader;
+ material_data->last_frame = false;
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
+
+RendererStorageRD::MaterialData *RendererSceneRenderRD::_create_fog_material_funcs(RendererStorageRD::ShaderData *p_shader) {
+ return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->_create_fog_material_func(static_cast<FogShaderData *>(p_shader));
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Volumetric Fog
+
void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) {
ERR_FAIL_COND(!rb->volumetric_fog);
@@ -3048,11 +3760,14 @@ void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) {
RD::get_singleton()->free(rb->volumetric_fog->light_density_map);
RD::get_singleton()->free(rb->volumetric_fog->fog_map);
- if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
- RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
+ if (rb->volumetric_fog->fog_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->fog_uniform_set)) {
+ RD::get_singleton()->free(rb->volumetric_fog->fog_uniform_set);
+ }
+ if (rb->volumetric_fog->process_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->process_uniform_set)) {
+ RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set);
}
- if (rb->volumetric_fog->uniform_set2.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set2)) {
- RD::get_singleton()->free(rb->volumetric_fog->uniform_set2);
+ if (rb->volumetric_fog->process_uniform_set2.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->process_uniform_set2)) {
+ RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set2);
}
if (rb->volumetric_fog->sdfgi_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->sdfgi_uniform_set)) {
RD::get_singleton()->free(rb->volumetric_fog->sdfgi_uniform_set);
@@ -3066,11 +3781,30 @@ void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) {
rb->volumetric_fog = nullptr;
}
-void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) {
+Vector3i RendererSceneRenderRD::_point_get_position_in_froxel_volume(const Vector3 &p_point, float fog_end, const Vector2 &fog_near_size, const Vector2 &fog_far_size, float volumetric_fog_detail_spread, const Vector3 &fog_size, const Transform3D &p_cam_transform) {
+ Vector3 view_position = p_cam_transform.affine_inverse().xform(p_point);
+ view_position.z = MIN(view_position.z, -0.01); // Clamp to the front of camera
+ Vector3 fog_position = Vector3(0, 0, 0);
+
+ view_position.y = -view_position.y;
+ fog_position.z = -view_position.z / fog_end;
+ fog_position.x = (view_position.x / (2 * (fog_near_size.x * (1.0 - fog_position.z) + fog_far_size.x * fog_position.z))) + 0.5;
+ fog_position.y = (view_position.y / (2 * (fog_near_size.y * (1.0 - fog_position.z) + fog_far_size.y * fog_position.z))) + 0.5;
+ fog_position.z = Math::pow(float(fog_position.z), float(1.0 / volumetric_fog_detail_spread));
+ fog_position = fog_position * fog_size - Vector3(0.5, 0.5, 0.5);
+
+ fog_position.x = CLAMP(fog_position.x, 0.0, fog_size.x);
+ fog_position.y = CLAMP(fog_position.y, 0.0, fog_size.y);
+ fog_position.z = CLAMP(fog_position.z, 0.0, fog_size.z);
+
+ return Vector3i(fog_position);
+}
+
+void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform3D &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes) {
ERR_FAIL_COND(!is_clustered_enabled()); // can't use volumetric fog without clustered
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND(!rb);
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_environment);
float ratio = float(rb->width) / float((rb->width + rb->height) / 2);
uint32_t target_width = uint32_t(float(volumetric_fog_size) * ratio);
@@ -3089,6 +3823,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
}
RENDER_TIMESTAMP(">Volumetric Fog");
+ RD::get_singleton()->draw_command_begin_label("Volumetric Fog");
if (env && env->volumetric_fog_enabled && !rb->volumetric_fog) {
//required volumetric fog but not existing, create
@@ -3106,15 +3841,43 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
rb->volumetric_fog->light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ RD::get_singleton()->set_resource_name(rb->volumetric_fog->light_density_map, "Fog light-density map");
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
rb->volumetric_fog->prev_light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ RD::get_singleton()->set_resource_name(rb->volumetric_fog->prev_light_density_map, "Fog previous light-density map");
RD::get_singleton()->texture_clear(rb->volumetric_fog->prev_light_density_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
rb->volumetric_fog->fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ RD::get_singleton()->set_resource_name(rb->volumetric_fog->fog_map, "Fog map");
+
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ Vector<uint8_t> dm;
+ dm.resize(target_width * target_height * volumetric_fog_depth * 4);
+ dm.fill(0);
+
+ rb->volumetric_fog->density_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm);
+ RD::get_singleton()->set_resource_name(rb->volumetric_fog->density_map, "Fog density map");
+ rb->volumetric_fog->light_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm);
+ RD::get_singleton()->set_resource_name(rb->volumetric_fog->light_map, "Fog light map");
+ rb->volumetric_fog->emissive_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm);
+ RD::get_singleton()->set_resource_name(rb->volumetric_fog->emissive_map, "Fog emissive map");
+#else
+ tf.format = RD::DATA_FORMAT_R32_UINT;
+ tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ rb->volumetric_fog->density_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ RD::get_singleton()->set_resource_name(rb->volumetric_fog->density_map, "Fog density map");
+ RD::get_singleton()->texture_clear(rb->volumetric_fog->density_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ rb->volumetric_fog->light_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ RD::get_singleton()->set_resource_name(rb->volumetric_fog->light_map, "Fog light map");
+ RD::get_singleton()->texture_clear(rb->volumetric_fog->light_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ rb->volumetric_fog->emissive_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ RD::get_singleton()->set_resource_name(rb->volumetric_fog->emissive_map, "Fog emissive map");
+ RD::get_singleton()->texture_clear(rb->volumetric_fog->emissive_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
+#endif
Vector<RD::Uniform> uniforms;
{
@@ -3128,18 +3891,216 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky.sky_shader.default_shader_rd, RendererSceneSkyRD::SKY_SET_FOG);
}
- //update volumetric fog
+ if (p_fog_volumes.size() > 0) {
+ RD::get_singleton()->draw_command_begin_label("Render Volumetric Fog Volumes");
- if (rb->volumetric_fog->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
- //re create uniform set if needed
+ RENDER_TIMESTAMP("Render Fog Volumes");
+
+ VolumetricFogShader::VolumeUBO params;
+
+ Vector2 frustum_near_size = p_cam_projection.get_viewport_half_extents();
+ Vector2 frustum_far_size = p_cam_projection.get_far_plane_half_extents();
+ float z_near = p_cam_projection.get_z_near();
+ float z_far = p_cam_projection.get_z_far();
+ float fog_end = env->volumetric_fog_length;
+
+ Vector2 fog_far_size = frustum_near_size.lerp(frustum_far_size, (fog_end - z_near) / (z_far - z_near));
+ Vector2 fog_near_size;
+ if (p_cam_projection.is_orthogonal()) {
+ fog_near_size = fog_far_size;
+ } else {
+ fog_near_size = Vector2();
+ }
+
+ params.fog_frustum_size_begin[0] = fog_near_size.x;
+ params.fog_frustum_size_begin[1] = fog_near_size.y;
+
+ params.fog_frustum_size_end[0] = fog_far_size.x;
+ params.fog_frustum_size_end[1] = fog_far_size.y;
+
+ params.fog_frustum_end = fog_end;
+ params.z_near = z_near;
+ params.z_far = z_far;
+ params.time = time;
+
+ params.fog_volume_size[0] = rb->volumetric_fog->width;
+ params.fog_volume_size[1] = rb->volumetric_fog->height;
+ params.fog_volume_size[2] = rb->volumetric_fog->depth;
+
+ params.use_temporal_reprojection = env->volumetric_fog_temporal_reprojection;
+ params.temporal_frame = RSG::rasterizer->get_frame_number() % VolumetricFog::MAX_TEMPORAL_FRAMES;
+ params.detail_spread = env->volumetric_fog_detail_spread;
+ params.temporal_blend = env->volumetric_fog_temporal_reprojection_amount;
+
+ Transform3D to_prev_cam_view = rb->volumetric_fog->prev_cam_transform.affine_inverse() * p_cam_transform;
+ storage->store_transform(to_prev_cam_view, params.to_prev_view);
+ storage->store_transform(p_cam_transform, params.transform);
+
+ RD::get_singleton()->buffer_update(volumetric_fog.volume_ubo, 0, sizeof(VolumetricFogShader::VolumeUBO), &params, RD::BARRIER_MASK_COMPUTE);
+
+ if (rb->volumetric_fog->fog_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->fog_uniform_set)) {
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+#else
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+#endif
+ u.binding = 1;
+ u.ids.push_back(rb->volumetric_fog->emissive_map);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 2;
+ u.ids.push_back(volumetric_fog.volume_ubo);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+#else
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+#endif
+ u.binding = 3;
+ u.ids.push_back(rb->volumetric_fog->density_map);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+#else
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+#endif
+ u.binding = 4;
+ u.ids.push_back(rb->volumetric_fog->light_map);
+ uniforms.push_back(u);
+ }
+
+ rb->volumetric_fog->fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.default_shader_rd, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS);
+ }
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ bool any_uses_time = false;
+
+ for (int i = 0; i < (int)p_fog_volumes.size(); i++) {
+ FogVolumeInstance *fog_volume_instance = fog_volume_instance_owner.get_or_null(p_fog_volumes[i]);
+ ERR_FAIL_COND(!fog_volume_instance);
+ RID fog_volume = fog_volume_instance->volume;
+
+ RID fog_material = storage->fog_volume_get_material(fog_volume);
+
+ FogMaterialData *material = nullptr;
+ if (fog_material.is_valid()) {
+ material = (FogMaterialData *)storage->material_get_data(fog_material, RendererStorageRD::SHADER_TYPE_FOG);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ fog_material = volumetric_fog.default_material;
+ material = (FogMaterialData *)storage->material_get_data(fog_material, RendererStorageRD::SHADER_TYPE_FOG);
+ }
+
+ ERR_FAIL_COND(!material);
+
+ FogShaderData *shader_data = material->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ any_uses_time |= shader_data->uses_time;
+
+ Vector3i min = Vector3i();
+ Vector3i max = Vector3i();
+ Vector3i kernel_size = Vector3i();
+
+ Vector3 position = fog_volume_instance->transform.get_origin();
+ RS::FogVolumeShape volume_type = storage->fog_volume_get_shape(fog_volume);
+ Vector3 extents = storage->fog_volume_get_extents(fog_volume);
+
+ if (volume_type == RS::FOG_VOLUME_SHAPE_BOX || volume_type == RS::FOG_VOLUME_SHAPE_ELLIPSOID) {
+ Vector3i points[8];
+ points[0] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform);
+ points[1] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform);
+ points[2] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform);
+ points[3] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform);
+ points[4] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform);
+ points[5] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform);
+ points[6] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform);
+ points[7] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform);
+
+ min = Vector3i(int32_t(rb->volumetric_fog->width) - 1, int32_t(rb->volumetric_fog->height) - 1, int32_t(rb->volumetric_fog->depth) - 1);
+ max = Vector3i(1, 1, 1);
+
+ for (int j = 0; j < 8; j++) {
+ min = Vector3i(MIN(min.x, points[j].x), MIN(min.y, points[j].y), MIN(min.z, points[j].z));
+ max = Vector3i(MAX(max.x, points[j].x), MAX(max.y, points[j].y), MAX(max.z, points[j].z));
+ }
+
+ kernel_size = max - min;
+ } else {
+ // Volume type global runs on all cells
+ extents = Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth);
+ min = Vector3i(0, 0, 0);
+ kernel_size = Vector3i(int32_t(rb->volumetric_fog->width), int32_t(rb->volumetric_fog->height), int32_t(rb->volumetric_fog->depth));
+ }
+
+ if (kernel_size.x == 0 || kernel_size.y == 0 || kernel_size.z == 0) {
+ continue;
+ }
+
+ volumetric_fog.push_constant.position[0] = position.x;
+ volumetric_fog.push_constant.position[1] = position.y;
+ volumetric_fog.push_constant.position[2] = position.z;
+ volumetric_fog.push_constant.extents[0] = extents.x;
+ volumetric_fog.push_constant.extents[1] = extents.y;
+ volumetric_fog.push_constant.extents[2] = extents.z;
+ volumetric_fog.push_constant.corner[0] = min.x;
+ volumetric_fog.push_constant.corner[1] = min.y;
+ volumetric_fog.push_constant.corner[2] = min.z;
+ volumetric_fog.push_constant.shape = uint32_t(storage->fog_volume_get_shape(fog_volume));
+ storage->store_transform(fog_volume_instance->transform.affine_inverse(), volumetric_fog.push_constant.transform);
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shader_data->pipeline);
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->fog_uniform_set, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &volumetric_fog.push_constant, sizeof(VolumetricFogShader::FogPushConstant));
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, volumetric_fog.base_uniform_set, VolumetricFogShader::FogSet::FOG_SET_BASE);
+ if (material->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material->uniform_set)) { // Material may not have a uniform set.
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, material->uniform_set, VolumetricFogShader::FogSet::FOG_SET_MATERIAL);
+ }
+
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, kernel_size.x, kernel_size.y, kernel_size.z);
+ }
+ if (any_uses_time || env->volumetric_fog_temporal_reprojection) {
+ RenderingServerDefault::redraw_request();
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+
+ RD::get_singleton()->compute_list_end();
+ }
+
+ if (rb->volumetric_fog->process_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->process_uniform_set)) {
+ //re create uniform set if needed
Vector<RD::Uniform> uniforms;
+ Vector<RD::Uniform> copy_uniforms;
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
if (shadow_atlas == nullptr || shadow_atlas->depth.is_null()) {
u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK));
} else {
@@ -3147,6 +4108,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
}
uniforms.push_back(u);
+ copy_uniforms.push_back(u);
}
{
@@ -3159,6 +4121,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK));
}
uniforms.push_back(u);
+ copy_uniforms.push_back(u);
}
{
@@ -3167,6 +4130,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 3;
u.ids.push_back(get_omni_light_buffer());
uniforms.push_back(u);
+ copy_uniforms.push_back(u);
}
{
RD::Uniform u;
@@ -3174,6 +4138,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 4;
u.ids.push_back(get_spot_light_buffer());
uniforms.push_back(u);
+ copy_uniforms.push_back(u);
}
{
@@ -3182,6 +4147,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 5;
u.ids.push_back(get_directional_light_buffer());
uniforms.push_back(u);
+ copy_uniforms.push_back(u);
}
{
@@ -3190,6 +4156,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 6;
u.ids.push_back(rb->cluster_builder->get_cluster_buffer());
uniforms.push_back(u);
+ copy_uniforms.push_back(u);
}
{
@@ -3198,6 +4165,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 7;
u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
uniforms.push_back(u);
+ copy_uniforms.push_back(u);
}
{
@@ -3206,6 +4174,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 8;
u.ids.push_back(rb->volumetric_fog->light_density_map);
uniforms.push_back(u);
+ copy_uniforms.push_back(u);
}
{
@@ -3218,28 +4187,39 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
{
RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 9;
+ u.ids.push_back(rb->volumetric_fog->prev_light_density_map);
+ copy_uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
u.binding = 10;
u.ids.push_back(shadow_sampler);
uniforms.push_back(u);
+ copy_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 11;
- u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers));
+ u.ids.push_back(render_buffers_get_voxel_gi_buffer(p_render_buffers));
uniforms.push_back(u);
+ copy_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 12;
- for (int i = 0; i < RendererSceneGIRD::MAX_GIPROBES; i++) {
- u.ids.push_back(rb->gi.giprobe_textures[i]);
+ for (int i = 0; i < RendererSceneGIRD::MAX_VOXEL_GI_INSTANCES; i++) {
+ u.ids.push_back(rb->gi.voxel_gi_textures[i]);
}
uniforms.push_back(u);
+ copy_uniforms.push_back(u);
}
{
RD::Uniform u;
@@ -3247,6 +4227,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 13;
u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
uniforms.push_back(u);
+ copy_uniforms.push_back(u);
}
{
RD::Uniform u;
@@ -3254,6 +4235,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 14;
u.ids.push_back(volumetric_fog.params_ubo);
uniforms.push_back(u);
+ copy_uniforms.push_back(u);
}
{
RD::Uniform u;
@@ -3262,12 +4244,58 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.ids.push_back(rb->volumetric_fog->prev_light_density_map);
uniforms.push_back(u);
}
+ {
+ RD::Uniform u;
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+#else
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+#endif
+ u.binding = 16;
+ u.ids.push_back(rb->volumetric_fog->density_map);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+#else
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+#endif
+ u.binding = 17;
+ u.ids.push_back(rb->volumetric_fog->light_map);
+ uniforms.push_back(u);
+ }
- rb->volumetric_fog->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, 0), 0);
+ {
+ RD::Uniform u;
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+#else
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+#endif
+ u.binding = 18;
+ u.ids.push_back(rb->volumetric_fog->emissive_map);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 19;
+ RID radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
+ RID sky_texture = env->sky.is_valid() ? sky.sky_get_radiance_texture_rd(env->sky) : RID();
+ u.ids.push_back(sky_texture.is_valid() ? sky_texture : radiance_texture);
+ uniforms.push_back(u);
+ }
+
+ rb->volumetric_fog->copy_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY), 0);
+
+ rb->volumetric_fog->process_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY), 0);
SWAP(uniforms.write[7].ids.write[0], uniforms.write[8].ids.write[0]);
- rb->volumetric_fog->uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, 0), 0);
+ rb->volumetric_fog->process_uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, 0), 0);
}
bool using_sdfgi = env->volumetric_fog_gi_inject > 0.0001 && env->sdfgi_enabled && (rb->sdfgi != nullptr);
@@ -3300,7 +4328,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
uniforms.push_back(u);
}
- rb->volumetric_fog->sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI), 1);
+ rb->volumetric_fog->sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI), 1);
}
}
@@ -3329,23 +4357,35 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
params.fog_frustum_size_end[0] = fog_far_size.x;
params.fog_frustum_size_end[1] = fog_far_size.y;
- params.z_near = z_near;
+ params.ambient_inject = env->volumetric_fog_ambient_inject * env->ambient_light_energy;
params.z_far = z_far;
params.fog_frustum_end = fog_end;
+ Color ambient_color = env->ambient_light.to_linear();
+ params.ambient_color[0] = ambient_color.r;
+ params.ambient_color[1] = ambient_color.g;
+ params.ambient_color[2] = ambient_color.b;
+ params.sky_contribution = env->ambient_sky_contribution;
+
params.fog_volume_size[0] = rb->volumetric_fog->width;
params.fog_volume_size[1] = rb->volumetric_fog->height;
params.fog_volume_size[2] = rb->volumetric_fog->depth;
params.directional_light_count = p_directional_light_count;
- Color light = env->volumetric_fog_light.to_linear();
- params.light_energy[0] = light.r * env->volumetric_fog_light_energy;
- params.light_energy[1] = light.g * env->volumetric_fog_light_energy;
- params.light_energy[2] = light.b * env->volumetric_fog_light_energy;
+ Color emission = env->volumetric_fog_emission.to_linear();
+ params.base_emission[0] = emission.r * env->volumetric_fog_emission_energy;
+ params.base_emission[1] = emission.g * env->volumetric_fog_emission_energy;
+ params.base_emission[2] = emission.b * env->volumetric_fog_emission_energy;
params.base_density = env->volumetric_fog_density;
+ Color base_scattering = env->volumetric_fog_scattering.to_linear();
+ params.base_scattering[0] = base_scattering.r;
+ params.base_scattering[1] = base_scattering.g;
+ params.base_scattering[2] = base_scattering.b;
+ params.phase_g = env->volumetric_fog_anisotropy;
+
params.detail_spread = env->volumetric_fog_detail_spread;
params.gi_inject = env->volumetric_fog_gi_inject;
@@ -3362,10 +4402,10 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
params.cam_rotation[10] = p_cam_transform.basis[2][2];
params.cam_rotation[11] = 0;
params.filter_axis = 0;
- params.max_gi_probes = env->volumetric_fog_gi_inject > 0.001 ? p_gi_probe_count : 0;
+ params.max_voxel_gi_instances = env->volumetric_fog_gi_inject > 0.001 ? p_voxel_gi_count : 0;
params.temporal_frame = RSG::rasterizer->get_frame_number() % VolumetricFog::MAX_TEMPORAL_FRAMES;
- Transform to_prev_cam_view = rb->volumetric_fog->prev_cam_transform.affine_inverse() * p_cam_transform;
+ Transform3D to_prev_cam_view = rb->volumetric_fog->prev_cam_transform.affine_inverse() * p_cam_transform;
storage->store_transform(to_prev_cam_view, params.to_prev_view);
params.use_temporal_reprojection = env->volumetric_fog_temporal_reprojection;
@@ -3385,10 +4425,9 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
params.screen_size[1] = rb->height;
}
- /* Vector2 dssize = directional_shadow_get_size();
- push_constant.directional_shadow_pixel_size[0] = 1.0 / dssize.x;
- push_constant.directional_shadow_pixel_size[1] = 1.0 / dssize.y;
-*/
+ Basis sky_transform = env->sky_orientation;
+ sky_transform = sky_transform.inverse() * p_cam_transform.basis;
+ RendererStorageRD::store_transform_3x3(sky_transform, params.radiance_inverse_xform);
RD::get_singleton()->draw_command_begin_label("Render Volumetric Fog");
@@ -3397,33 +4436,32 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- bool use_filter = volumetric_fog_filter_active;
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[using_sdfgi ? VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI : VOLUMETRIC_FOG_SHADER_DENSITY]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[using_sdfgi ? VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI : VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set, 0);
if (using_sdfgi) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->sdfgi_uniform_set, 1);
}
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ // Copy fog to history buffer
+ if (env->volumetric_fog_temporal_reprojection) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->copy_uniform_set, 0);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ }
RD::get_singleton()->draw_command_end_label();
- RD::get_singleton()->compute_list_end();
-
- RD::get_singleton()->texture_copy(rb->volumetric_fog->light_density_map, rb->volumetric_fog->prev_light_density_map, Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), 0, 0, 0, 0);
-
- compute_list = RD::get_singleton()->compute_list_begin();
-
- if (use_filter) {
+ if (volumetric_fog_filter_active) {
RD::get_singleton()->draw_command_begin_label("Filter Fog");
RENDER_TIMESTAMP("Filter Fog");
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FILTER]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0);
-
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set, 0);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth);
RD::get_singleton()->compute_list_end();
@@ -3433,11 +4471,8 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), &params);
compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FILTER]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set2, 0);
- if (using_sdfgi) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->sdfgi_uniform_set, 1);
- }
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set2, 0);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth);
RD::get_singleton()->compute_list_add_barrier(compute_list);
@@ -3447,21 +4482,22 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
RENDER_TIMESTAMP("Integrate Fog");
RD::get_singleton()->draw_command_begin_label("Integrate Fog");
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FOG]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set, 0);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, 1);
RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_RASTER);
RENDER_TIMESTAMP("<Volumetric Fog");
RD::get_singleton()->draw_command_end_label();
+ RD::get_singleton()->draw_command_end_label();
rb->volumetric_fog->prev_cam_transform = p_cam_transform;
}
bool RendererSceneRenderRD::_needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi) {
if (p_render_data->render_buffers.is_valid()) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
if (rb->sdfgi != nullptr) {
return true;
}
@@ -3472,14 +4508,14 @@ bool RendererSceneRenderRD::_needs_post_prepass_render(RenderDataRD *p_render_da
void RendererSceneRenderRD::_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi) {
if (p_render_data->render_buffers.is_valid()) {
if (p_use_gi) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
ERR_FAIL_COND(rb == nullptr);
if (rb->sdfgi == nullptr) {
return;
}
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_render_data->environment);
- rb->sdfgi->update_probes(env, sky.sky_owner.getornull(env->sky));
+ RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_render_data->environment);
+ rb->sdfgi->update_probes(env, sky.sky_owner.get_or_null(env->sky));
}
}
}
@@ -3492,29 +4528,26 @@ void RendererSceneRenderRD::_pre_resolve_render(RenderDataRD *p_render_data, boo
}
}
-void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_gi_probe_buffer) {
+void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer) {
// Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time
if (p_render_data->render_buffers.is_valid() && p_use_gi) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
ERR_FAIL_COND(rb == nullptr);
- if (rb->sdfgi == nullptr) {
- return;
+ if (rb->sdfgi != nullptr) {
+ rb->sdfgi->store_probes();
}
-
- rb->sdfgi->store_probes();
}
render_state.cube_shadows.clear();
render_state.shadows.clear();
render_state.directional_shadows.clear();
- Plane camera_plane(p_render_data->cam_transform.origin, -p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z));
+ Plane camera_plane(-p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z), p_render_data->cam_transform.origin);
float lod_distance_multiplier = p_render_data->cam_projection.get_lod_multiplier();
-
{
for (int i = 0; i < render_state.render_shadow_count; i++) {
- LightInstance *li = light_instance_owner.getornull(render_state.render_shadows[i].light);
+ LightInstance *li = light_instance_owner.get_or_null(render_state.render_shadows[i].light);
if (storage->light_get_type(li->light) == RS::LIGHT_DIRECTIONAL) {
render_state.directional_shadows.push_back(i);
@@ -3527,7 +4560,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
//cube shadows are rendered in their own way
for (uint32_t i = 0; i < render_state.cube_shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, true, true, true);
+ _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, true, true, true, p_render_data->render_info);
}
if (render_state.directional_shadows.size()) {
@@ -3557,11 +4590,11 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
//render directional shadows
for (uint32_t i = 0; i < render_state.directional_shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false);
+ _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false, p_render_data->render_info);
}
//render positional shadows
for (uint32_t i = 0; i < render_state.shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true);
+ _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true, p_render_data->render_info);
}
_render_shadow_process();
@@ -3569,7 +4602,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
//start GI
if (render_gi) {
- gi.process_gi(p_render_data->render_buffers, p_normal_roughness_buffer, p_gi_probe_buffer, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, *p_render_data->gi_probes, this);
+ gi.process_gi(p_render_data->render_buffers, p_normal_roughness_buffer, p_voxel_gi_buffer, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, *p_render_data->voxel_gi_instances, this);
}
//Do shadow rendering (in parallel with GI)
@@ -3607,7 +4640,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
uint32_t directional_light_count = 0;
uint32_t positional_light_count = 0;
- _setup_lights(*p_render_data->lights, p_render_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count);
+ _setup_lights(*p_render_data->lights, p_render_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
_setup_decals(*p_render_data->decals, p_render_data->cam_transform.affine_inverse());
p_render_data->directional_light_count = directional_light_count;
@@ -3625,16 +4658,16 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
}
}
if (is_volumetric_supported()) {
- _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.gi_probe_count);
+ _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.voxel_gi_count, *p_render_data->fog_volumes);
}
}
}
-void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data) {
+void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) {
// getting this here now so we can direct call a bunch of things more easily
RenderBuffers *rb = nullptr;
if (p_render_buffers.is_valid()) {
- rb = render_buffers_owner.getornull(p_render_buffers);
+ rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND(!rb);
}
@@ -3643,18 +4676,27 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
{
render_data.render_buffers = p_render_buffers;
- render_data.cam_transform = p_cam_transform;
- render_data.cam_projection = p_cam_projection;
- render_data.cam_ortogonal = p_cam_projection.is_orthogonal(); // !BAS! Shouldn't this be p_cam_ortogonal ?
- render_data.z_near = p_cam_projection.get_z_near();
- render_data.z_far = p_cam_projection.get_z_far();
+ // Our first camera is used by default
+ render_data.cam_transform = p_camera_data->main_transform;
+ render_data.cam_projection = p_camera_data->main_projection;
+ render_data.view_projection[0] = p_camera_data->main_projection;
+ render_data.cam_ortogonal = p_camera_data->is_ortogonal;
+
+ render_data.view_count = p_camera_data->view_count;
+ for (uint32_t v = 0; v < p_camera_data->view_count; v++) {
+ render_data.view_projection[v] = p_camera_data->view_projection[v];
+ }
+
+ render_data.z_near = p_camera_data->main_projection.get_z_near();
+ render_data.z_far = p_camera_data->main_projection.get_z_far();
render_data.instances = &p_instances;
render_data.lights = &p_lights;
render_data.reflection_probes = &p_reflection_probes;
- render_data.gi_probes = &p_gi_probes;
+ render_data.voxel_gi_instances = &p_voxel_gi_instances;
render_data.decals = &p_decals;
render_data.lightmaps = &p_lightmaps;
+ render_data.fog_volumes = &p_fog_volumes;
render_data.environment = p_environment;
render_data.camera_effects = p_camera_effects;
render_data.shadow_atlas = p_shadow_atlas;
@@ -3662,8 +4704,9 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
render_data.reflection_probe = p_reflection_probe;
render_data.reflection_probe_pass = p_reflection_probe_pass;
- render_data.lod_distance_multiplier = p_cam_projection.get_lod_multiplier();
- render_data.lod_camera_plane = Plane(p_cam_transform.get_origin(), -p_cam_transform.basis.get_axis(Vector3::AXIS_Z));
+ // this should be the same for all cameras..
+ render_data.lod_distance_multiplier = p_camera_data->main_projection.get_lod_multiplier();
+ render_data.lod_camera_plane = Plane(-p_camera_data->main_transform.basis.get_axis(Vector3::AXIS_Z), p_camera_data->main_transform.get_origin());
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
render_data.screen_lod_threshold = 0.0;
@@ -3676,6 +4719,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
render_state.render_sdfgi_regions = p_render_sdfgi_regions;
render_state.render_sdfgi_region_count = p_render_sdfgi_region_count;
render_state.sdfgi_update_data = p_sdfgi_update_data;
+ render_data.render_info = r_render_info;
}
PagedArray<RID> empty;
@@ -3683,7 +4727,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
render_data.lights = &empty;
render_data.reflection_probes = &empty;
- render_data.gi_probes = &empty;
+ render_data.voxel_gi_instances = &empty;
}
//sdfgi first
@@ -3703,12 +4747,12 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
clear_color = storage->get_default_clear_color();
}
- //assign render indices to giprobes
+ //assign render indices to voxel_gi_instances
if (is_dynamic_gi_supported()) {
- for (uint32_t i = 0; i < (uint32_t)p_gi_probes.size(); i++) {
- RendererSceneGIRD::GIProbeInstance *giprobe_inst = gi.gi_probe_instance_owner.getornull(p_gi_probes[i]);
- if (giprobe_inst) {
- giprobe_inst->render_index = i;
+ for (uint32_t i = 0; i < (uint32_t)p_voxel_gi_instances.size(); i++) {
+ RendererSceneGIRD::VoxelGIInstance *voxel_gi_inst = gi.voxel_gi_instance_owner.get_or_null(p_voxel_gi_instances[i]);
+ if (voxel_gi_inst) {
+ voxel_gi_inst->render_index = i;
}
}
}
@@ -3717,8 +4761,8 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
// render_data.render_buffers == p_render_buffers so we can use our already retrieved rb
current_cluster_builder = rb->cluster_builder;
} else if (reflection_probe_instance_owner.owns(render_data.reflection_probe)) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(render_data.reflection_probe);
- ReflectionAtlas *ra = reflection_atlas_owner.getornull(rpi->atlas);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(render_data.reflection_probe);
+ ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(rpi->atlas);
if (!ra) {
ERR_PRINT("reflection probe has no reflection atlas! Bug?");
current_cluster_builder = nullptr;
@@ -3730,17 +4774,16 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
current_cluster_builder = nullptr;
}
- if (rb != nullptr && rb->sdfgi != nullptr) {
- rb->sdfgi->update_cascades();
-
- rb->sdfgi->pre_process_gi(p_cam_transform, &render_data, this);
- }
+ render_state.voxel_gi_count = 0;
- render_state.gi_probe_count = 0;
- if (rb != nullptr && rb->sdfgi != nullptr) {
- gi.setup_giprobes(render_data.render_buffers, render_data.cam_transform, *render_data.gi_probes, render_state.gi_probe_count, this);
+ if (rb != nullptr && is_dynamic_gi_supported()) {
+ if (rb->sdfgi) {
+ rb->sdfgi->update_cascades();
+ rb->sdfgi->pre_process_gi(render_data.cam_transform, &render_data, this);
+ rb->sdfgi->update_light();
+ }
- rb->sdfgi->update_light();
+ gi.setup_voxel_gi_instances(render_data.render_buffers, render_data.cam_transform, *render_data.voxel_gi_instances, render_state.voxel_gi_count, this);
}
render_state.depth_prepass_used = false;
@@ -3754,9 +4797,26 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
_render_scene(&render_data, clear_color);
if (p_render_buffers.is_valid()) {
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) {
+ /*
+ _debug_draw_cluster(p_render_buffers);
+ RENDER_TIMESTAMP("Tonemap");
+ _render_buffers_post_process_and_tonemap(&render_data);
+ */
+
+ _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex);
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb != nullptr && rb->sdfgi != nullptr) {
+ rb->sdfgi->debug_draw(render_data.cam_projection, render_data.cam_transform, rb->width, rb->height, rb->render_target, rb->texture);
+ }
+ }
+}
+
+void RendererSceneRenderRD::_debug_draw_cluster(RID p_render_buffers) {
+ if (p_render_buffers.is_valid() && current_cluster_builder != nullptr) {
+ RS::ViewportDebugDraw dd = get_debug_draw_mode();
+
+ if (dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) {
ClusterBuilderRD::ElementType elem_type = ClusterBuilderRD::ELEMENT_TYPE_MAX;
- switch (debug_draw) {
+ switch (dd) {
case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS:
elem_type = ClusterBuilderRD::ELEMENT_TYPE_OMNI_LIGHT;
break;
@@ -3772,23 +4832,13 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
default: {
}
}
- if (current_cluster_builder != nullptr) {
- current_cluster_builder->debug(elem_type);
- }
- }
-
- RENDER_TIMESTAMP("Tonemap");
-
- _render_buffers_post_process_and_tonemap(&render_data);
- _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex);
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb != nullptr && rb->sdfgi != nullptr) {
- rb->sdfgi->debug_draw(p_cam_projection, p_cam_transform, rb->width, rb->height, rb->render_target, rb->texture);
+ current_cluster_builder->debug(elem_type);
}
}
}
-void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region) {
- LightInstance *light_instance = light_instance_owner.getornull(p_light);
+void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RendererScene::RenderInfo *p_render_info) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light);
ERR_FAIL_COND(!light_instance);
Rect2i atlas_rect;
@@ -3797,6 +4847,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
bool using_dual_paraboloid = false;
bool using_dual_paraboloid_flip = false;
+ Vector2i dual_paraboloid_offset;
RID render_fb;
RID render_texture;
float zfar;
@@ -3808,7 +4859,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
bool flip_y = false;
CameraMatrix light_projection;
- Transform light_transform;
+ Transform3D light_transform;
if (storage->light_get_type(light_instance->light) == RS::LIGHT_DIRECTIONAL) {
//set pssm stuff
@@ -3822,10 +4873,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
light_projection = light_instance->shadow_transform[p_pass].camera;
light_transform = light_instance->shadow_transform[p_pass].transform;
- atlas_rect.position.x = light_instance->directional_rect.position.x;
- atlas_rect.position.y = light_instance->directional_rect.position.y;
- atlas_rect.size.width = light_instance->directional_rect.size.x;
- atlas_rect.size.height = light_instance->directional_rect.size.y;
+ atlas_rect = light_instance->directional_rect;
if (storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
atlas_rect.size.width /= 2;
@@ -3836,8 +4884,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
} else if (p_pass == 2) {
atlas_rect.position.y += atlas_rect.size.height;
} else if (p_pass == 3) {
- atlas_rect.position.x += atlas_rect.size.width;
- atlas_rect.position.y += atlas_rect.size.height;
+ atlas_rect.position += atlas_rect.size;
}
} else if (storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
atlas_rect.size.height /= 2;
@@ -3862,7 +4909,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
} else {
//set from shadow atlas
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
ERR_FAIL_COND(!shadow_atlas);
ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light));
@@ -3890,6 +4937,9 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
zfar = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE);
if (storage->light_get_type(light_instance->light) == RS::LIGHT_OMNI) {
+ bool wrap = (shadow + 1) % shadow_atlas->quadrants[quadrant].subdivision == 0;
+ dual_paraboloid_offset = wrap ? Vector2i(1 - shadow_atlas->quadrants[quadrant].subdivision, 1) : Vector2i(1, 0);
+
if (storage->light_omni_get_shadow_mode(light_instance->light) == RS::LIGHT_OMNI_SHADOW_CUBE) {
ShadowCubemap *cubemap = _get_shadow_cubemap(shadow_size / 2);
@@ -3909,12 +4959,16 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
}
} else {
+ atlas_rect.position.x += 1;
+ atlas_rect.position.y += 1;
+ atlas_rect.size.x -= 2;
+ atlas_rect.size.y -= 2;
+
+ atlas_rect.position += p_pass * atlas_rect.size * dual_paraboloid_offset;
+
light_projection = light_instance->shadow_transform[0].camera;
light_transform = light_instance->shadow_transform[0].transform;
- atlas_rect.size.height /= 2;
- atlas_rect.position.y += p_pass * atlas_rect.size.height;
-
using_dual_paraboloid = true;
using_dual_paraboloid_flip = p_pass == 1;
render_fb = shadow_atlas->fb;
@@ -3933,20 +4987,17 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
if (render_cubemap) {
//rendering to cubemap
- _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, Rect2(), false, true, true, true);
+ _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, Rect2(), false, true, true, true, p_render_info);
if (finalize_cubemap) {
_render_shadow_process();
_render_shadow_end();
//reblit
Rect2 atlas_rect_norm = atlas_rect;
- atlas_rect_norm.position.x /= float(atlas_size);
- atlas_rect_norm.position.y /= float(atlas_size);
- atlas_rect_norm.size.x /= float(atlas_size);
- atlas_rect_norm.size.y /= float(atlas_size);
- atlas_rect_norm.size.height /= 2;
- storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, light_projection.get_z_near(), light_projection.get_z_far(), false);
- atlas_rect_norm.position.y += atlas_rect_norm.size.height;
- storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, light_projection.get_z_near(), light_projection.get_z_far(), true);
+ atlas_rect_norm.position /= float(atlas_size);
+ atlas_rect_norm.size /= float(atlas_size);
+ storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false);
+ atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size;
+ storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true);
//restore transform so it can be properly used
light_instance_set_shadow_transform(p_light, CameraMatrix(), light_instance->transform, zfar, 0, 0, 0);
@@ -3954,15 +5005,15 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
} else {
//render shadow
- _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass);
+ _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info);
}
}
-void RendererSceneRenderRD::render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+void RendererSceneRenderRD::render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
_render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, p_framebuffer, p_region);
}
-void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) {
+void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) {
ERR_FAIL_COND(!storage->particles_collision_is_heightfield(p_collider));
Vector3 extents = storage->particles_collision_get_extents(p_collider) * p_transform.basis.get_scale();
CameraMatrix cm;
@@ -3971,7 +5022,7 @@ void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider,
Vector3 cam_pos = p_transform.origin;
cam_pos.y += extents.y;
- Transform cam_xform;
+ Transform3D cam_xform;
cam_xform.set_look_at(cam_pos, cam_pos - p_transform.basis.get_axis(Vector3::AXIS_Y), -p_transform.basis.get_axis(Vector3::AXIS_Z).normalized());
RID fb = storage->particles_collision_get_heightfield_framebuffer(p_collider);
@@ -3981,7 +5032,7 @@ void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider,
bool RendererSceneRenderRD::free(RID p_rid) {
if (render_buffers_owner.owns(p_rid)) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_rid);
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_rid);
_free_render_buffer_data(rb);
memdelete(rb->data);
if (rb->sdfgi) {
@@ -4004,57 +5055,69 @@ bool RendererSceneRenderRD::free(RID p_rid) {
camera_effects_owner.free(p_rid);
} else if (reflection_atlas_owner.owns(p_rid)) {
reflection_atlas_set_size(p_rid, 0, 0);
- ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_rid);
+ ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_rid);
if (ra->cluster_builder) {
memdelete(ra->cluster_builder);
}
reflection_atlas_owner.free(p_rid);
} else if (reflection_probe_instance_owner.owns(p_rid)) {
- //not much to delete, just free it
- //ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_rid);
+ _free_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id);
reflection_probe_release_atlas_index(p_rid);
reflection_probe_instance_owner.free(p_rid);
} else if (decal_instance_owner.owns(p_rid)) {
+ DecalInstance *di = decal_instance_owner.get_or_null(p_rid);
+ _free_forward_id(FORWARD_ID_TYPE_DECAL, di->forward_id);
decal_instance_owner.free(p_rid);
} else if (lightmap_instance_owner.owns(p_rid)) {
lightmap_instance_owner.free(p_rid);
- } else if (gi.gi_probe_instance_owner.owns(p_rid)) {
- RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_rid);
- if (gi_probe->texture.is_valid()) {
- RD::get_singleton()->free(gi_probe->texture);
- RD::get_singleton()->free(gi_probe->write_buffer);
+ } else if (gi.voxel_gi_instance_owner.owns(p_rid)) {
+ RendererSceneGIRD::VoxelGIInstance *voxel_gi = gi.voxel_gi_instance_owner.get_or_null(p_rid);
+ if (voxel_gi->texture.is_valid()) {
+ RD::get_singleton()->free(voxel_gi->texture);
+ RD::get_singleton()->free(voxel_gi->write_buffer);
}
- for (int i = 0; i < gi_probe->dynamic_maps.size(); i++) {
- RD::get_singleton()->free(gi_probe->dynamic_maps[i].texture);
- RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth);
+ for (int i = 0; i < voxel_gi->dynamic_maps.size(); i++) {
+ RD::get_singleton()->free(voxel_gi->dynamic_maps[i].texture);
+ RD::get_singleton()->free(voxel_gi->dynamic_maps[i].depth);
}
- gi.gi_probe_instance_owner.free(p_rid);
+ gi.voxel_gi_instance_owner.free(p_rid);
} else if (sky.sky_owner.owns(p_rid)) {
sky.update_dirty_skys();
sky.free_sky(p_rid);
} else if (light_instance_owner.owns(p_rid)) {
- LightInstance *light_instance = light_instance_owner.getornull(p_rid);
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_rid);
//remove from shadow atlases..
for (Set<RID>::Element *E = light_instance->shadow_atlases.front(); E; E = E->next()) {
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(E->get());
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(E->get());
ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_rid));
uint32_t key = shadow_atlas->shadow_owners[p_rid];
uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK;
shadow_atlas->quadrants[q].shadows.write[s].owner = RID();
+
+ if (key & ShadowAtlas::OMNI_LIGHT_FLAG) {
+ // Omni lights use two atlas spots, make sure to clear the other as well
+ shadow_atlas->quadrants[q].shadows.write[s + 1].owner = RID();
+ }
+
shadow_atlas->shadow_owners.erase(p_rid);
}
+ if (light_instance->light_type != RS::LIGHT_DIRECTIONAL) {
+ _free_forward_id(light_instance->light_type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id);
+ }
light_instance_owner.free(p_rid);
} else if (shadow_atlas_owner.owns(p_rid)) {
shadow_atlas_set_size(p_rid, 0);
shadow_atlas_owner.free(p_rid);
-
+ } else if (fog_volume_instance_owner.owns(p_rid)) {
+ fog_volume_instance_owner.free(p_rid);
} else {
return false;
}
@@ -4153,7 +5216,7 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vecto
{
PackedByteArray data = RD::get_singleton()->texture_get_data(albedo_alpha_tex, 0);
Ref<Image> img;
- img.instance();
+ img.instantiate();
img->create(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBA8, data);
RD::get_singleton()->free(albedo_alpha_tex);
ret.push_back(img);
@@ -4162,7 +5225,7 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vecto
{
PackedByteArray data = RD::get_singleton()->texture_get_data(normal_tex, 0);
Ref<Image> img;
- img.instance();
+ img.instantiate();
img->create(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBA8, data);
RD::get_singleton()->free(normal_tex);
ret.push_back(img);
@@ -4171,7 +5234,7 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vecto
{
PackedByteArray data = RD::get_singleton()->texture_get_data(orm_tex, 0);
Ref<Image> img;
- img.instance();
+ img.instantiate();
img->create(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBA8, data);
RD::get_singleton()->free(orm_tex);
ret.push_back(img);
@@ -4180,7 +5243,7 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vecto
{
PackedByteArray data = RD::get_singleton()->texture_get_data(emission_tex, 0);
Ref<Image> img;
- img.instance();
+ img.instantiate();
img->create(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBAH, data);
RD::get_singleton()->free(emission_tex);
ret.push_back(img);
@@ -4240,10 +5303,12 @@ uint32_t RendererSceneRenderRD::get_max_elements() const {
}
RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
- max_cluster_elements = get_max_elements();
-
storage = p_storage;
singleton = this;
+}
+
+void RendererSceneRenderRD::init() {
+ max_cluster_elements = get_max_elements();
directional_shadow.size = GLOBAL_GET("rendering/shadows/directional_shadow/size");
directional_shadow.use_16_bits = GLOBAL_GET("rendering/shadows/directional_shadow/16_bits");
@@ -4293,18 +5358,124 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
}
if (is_volumetric_supported()) {
- String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n";
- Vector<String> volumetric_fog_modes;
- volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n");
- volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n#define ENABLE_SDFGI\n");
- volumetric_fog_modes.push_back("\n#define MODE_FILTER\n");
- volumetric_fog_modes.push_back("\n#define MODE_FOG\n");
- volumetric_fog.shader.initialize(volumetric_fog_modes, defines);
- volumetric_fog.shader_version = volumetric_fog.shader.version_create();
- for (int i = 0; i < VOLUMETRIC_FOG_SHADER_MAX; i++) {
- volumetric_fog.pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, i));
+ {
+ // Initialize local fog shader
+ Vector<String> volumetric_fog_modes;
+ volumetric_fog_modes.push_back("");
+ volumetric_fog.shader.initialize(volumetric_fog_modes);
+
+ storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_FOG, _create_fog_shader_funcs);
+ storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_FOG, _create_fog_material_funcs);
+ volumetric_fog.volume_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::VolumeUBO));
+ }
+
+ {
+ ShaderCompilerRD::DefaultIdentifierActions actions;
+
+ actions.renames["TIME"] = "scene_params.time";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
+ actions.renames["WORLD_POSITION"] = "world.xyz";
+ actions.renames["OBJECT_POSITION"] = "params.position";
+ actions.renames["UVW"] = "uvw";
+ actions.renames["EXTENTS"] = "params.extents";
+ actions.renames["ALBEDO"] = "albedo";
+ actions.renames["DENSITY"] = "density";
+ actions.renames["EMISSION"] = "emission";
+ actions.renames["SDF"] = "sdf";
+
+ actions.usage_defines["SDF"] = "#define SDF_USED\n";
+ actions.usage_defines["DENSITY"] = "#define DENSITY_USED\n";
+ actions.usage_defines["ALBEDO"] = "#define ALBEDO_USED\n";
+ actions.usage_defines["EMISSION"] = "#define EMISSION_USED\n";
+
+ actions.sampler_array_name = "material_samplers";
+ actions.base_texture_binding_index = 1;
+ actions.texture_layout_set = VolumetricFogShader::FogSet::FOG_SET_MATERIAL;
+ actions.base_uniform_string = "material.";
+
+ actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
+ actions.default_repeat = ShaderLanguage::REPEAT_DISABLE;
+ actions.global_buffer_array_variable = "global_variables.data";
+
+ volumetric_fog.compiler.initialize(actions);
+ }
+
+ {
+ // default material and shader for fog shader
+ volumetric_fog.default_shader = storage->shader_allocate();
+ storage->shader_initialize(volumetric_fog.default_shader);
+ storage->shader_set_code(volumetric_fog.default_shader, R"(
+// Default fog shader.
+
+shader_type fog;
+
+void fog() {
+ DENSITY = 1.0;
+ ALBEDO = vec3(1.0);
+}
+)");
+ volumetric_fog.default_material = storage->material_allocate();
+ storage->material_initialize(volumetric_fog.default_material);
+ storage->material_set_shader(volumetric_fog.default_material, volumetric_fog.default_shader);
+
+ FogMaterialData *md = (FogMaterialData *)storage->material_get_data(volumetric_fog.default_material, RendererStorageRD::SHADER_TYPE_FOG);
+ volumetric_fog.default_shader_rd = volumetric_fog.shader.version_get_shader(md->shader_data->version, 0);
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 1;
+ u.ids.resize(12);
+ RID *ids_ptr = u.ids.ptrw();
+ ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 2;
+ u.ids.push_back(storage->global_variables_get_storage_buffer());
+ uniforms.push_back(u);
+ }
+
+ volumetric_fog.base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.default_shader_rd, VolumetricFogShader::FogSet::FOG_SET_BASE);
+ }
+ {
+ String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n";
+ defines += "\n#define MAX_SKY_LOD " + itos(get_roughness_layers() - 1) + ".0\n";
+ if (is_using_radiance_cubemap_array()) {
+ defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";
+ }
+ Vector<String> volumetric_fog_modes;
+ volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n");
+ volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n#define ENABLE_SDFGI\n");
+ volumetric_fog_modes.push_back("\n#define MODE_FILTER\n");
+ volumetric_fog_modes.push_back("\n#define MODE_FOG\n");
+ volumetric_fog_modes.push_back("\n#define MODE_COPY\n");
+
+ volumetric_fog.process_shader.initialize(volumetric_fog_modes, defines);
+ volumetric_fog.process_shader_version = volumetric_fog.process_shader.version_create();
+ for (int i = 0; i < VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_MAX; i++) {
+ volumetric_fog.process_pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, i));
+ }
+ volumetric_fog.params_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::ParamsUBO));
}
- volumetric_fog.params_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::ParamsUBO));
}
{
@@ -4338,12 +5509,15 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/environment/volumetric_fog/volume_size"), GLOBAL_GET("rendering/environment/volumetric_fog/volume_depth"));
environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter"));
+ decals_set_filter(RS::DecalFilter(int(GLOBAL_GET("rendering/textures/decals/filter"))));
+ light_projectors_set_filter(RS::LightProjectorFilter(int(GLOBAL_GET("rendering/textures/light_projectors/filter"))));
+
cull_argument.set_page_pool(&cull_argument_pool);
}
RendererSceneRenderRD::~RendererSceneRenderRD() {
- for (Map<int, ShadowCubemap>::Element *E = shadow_cubemaps.front(); E; E = E->next()) {
- RD::get_singleton()->free(E->get().cubemap);
+ for (const KeyValue<int, ShadowCubemap> &E : shadow_cubemaps) {
+ RD::get_singleton()->free(E.value.cubemap);
}
if (sky.sky_scene_state.uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky.sky_scene_state.uniform_set)) {
@@ -4352,9 +5526,14 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {
if (is_dynamic_gi_supported()) {
gi.free();
+ }
- volumetric_fog.shader.version_free(volumetric_fog.shader_version);
+ if (is_volumetric_supported()) {
+ volumetric_fog.process_shader.version_free(volumetric_fog.process_shader_version);
+ RD::get_singleton()->free(volumetric_fog.volume_ubo);
RD::get_singleton()->free(volumetric_fog.params_ubo);
+ storage->free(volumetric_fog.default_shader);
+ storage->free(volumetric_fog.default_material);
}
RendererSceneSkyRD::SkyMaterialData *md = (RendererSceneSkyRD::SkyMaterialData *)storage->material_get_data(sky.sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY);
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 1f82ae6dec..98ab1a2c3c 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -40,25 +40,32 @@
#include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h"
#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
#include "servers/rendering/renderer_rd/shaders/volumetric_fog.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl.gen.h"
+#include "servers/rendering/renderer_scene.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
struct RenderDataRD {
RID render_buffers = RID();
- Transform cam_transform = Transform();
+ Transform3D cam_transform = Transform3D();
CameraMatrix cam_projection = CameraMatrix();
bool cam_ortogonal = false;
+ // For stereo rendering
+ uint32_t view_count = 1;
+ CameraMatrix view_projection[RendererSceneRender::MAX_RENDER_VIEWS];
+
float z_near = 0.0;
float z_far = 0.0;
const PagedArray<RendererSceneRender::GeometryInstance *> *instances = nullptr;
const PagedArray<RID> *lights = nullptr;
const PagedArray<RID> *reflection_probes = nullptr;
- const PagedArray<RID> *gi_probes = nullptr;
+ const PagedArray<RID> *voxel_gi_instances = nullptr;
const PagedArray<RID> *decals = nullptr;
const PagedArray<RID> *lightmaps = nullptr;
+ const PagedArray<RID> *fog_volumes = nullptr;
RID environment = RID();
RID camera_effects = RID();
RID shadow_atlas = RID();
@@ -75,6 +82,9 @@ struct RenderDataRD {
uint32_t cluster_max_elements = 0;
uint32_t directional_light_count = 0;
+ bool directional_light_soft_shadows = false;
+
+ RendererScene::RenderInfo *render_info = nullptr;
};
class RendererSceneRenderRD : public RendererSceneRender {
@@ -87,28 +97,29 @@ protected:
double time_step = 0;
struct RenderBufferData {
- virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) = 0;
+ virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) = 0;
virtual ~RenderBufferData() {}
};
virtual RenderBufferData *_create_render_buffer_data() = 0;
- void _setup_lights(const PagedArray<RID> &p_lights, const Transform &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count);
- void _setup_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform);
- void _setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment);
+ void _setup_lights(const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows);
+ void _setup_decals(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform);
+ void _setup_reflections(const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment);
virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0;
virtual void _render_shadow_begin() = 0;
- virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, 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, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true) = 0;
+ virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &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, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RendererScene::RenderInfo *p_render_info = nullptr) = 0;
virtual void _render_shadow_process() = 0;
virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) = 0;
- virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
+ virtual void _render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0;
- virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) = 0;
+ virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) = 0;
void _debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform);
+ void _debug_draw_cluster(RID p_render_buffers);
RenderBufferData *render_buffers_get_data(RID p_render_buffers);
@@ -123,7 +134,13 @@ protected:
void _post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi);
void _pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi);
- void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_gi_probe_buffer);
+ void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer);
+
+ void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data);
+ void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data);
+ void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data);
+ void _post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data);
+ void _disable_clear_request(const RenderDataRD *p_render_data);
// needed for a single argument calls (material and uv2)
PagedArrayPool<GeometryInstance *> cull_argument_pool;
@@ -134,11 +151,30 @@ protected:
RendererSceneEnvironmentRD *get_environment(RID p_environment) {
if (p_environment.is_valid()) {
- return environment_owner.getornull(p_environment);
+ return environment_owner.get_or_null(p_environment);
} else {
return nullptr;
}
- }
+ };
+
+ //used for mobile renderer mostly
+
+ typedef int32_t ForwardID;
+
+ enum ForwardIDType {
+ FORWARD_ID_TYPE_OMNI_LIGHT,
+ FORWARD_ID_TYPE_SPOT_LIGHT,
+ FORWARD_ID_TYPE_REFLECTION_PROBE,
+ FORWARD_ID_TYPE_DECAL,
+ FORWARD_ID_MAX,
+ };
+
+ virtual ForwardID _allocate_forward_id(ForwardIDType p_type) { return -1; }
+ virtual void _free_forward_id(ForwardIDType p_type, ForwardID p_id) {}
+ virtual void _map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) {}
+ virtual bool _uses_forward_ids() const { return false; }
+
+ virtual void _update_shader_quality_settings() {}
private:
RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
@@ -181,10 +217,11 @@ private:
uint32_t render_step = 0;
uint64_t last_pass = 0;
- uint32_t render_index = 0;
uint32_t cull_mask = 0;
- Transform transform;
+ ForwardID forward_id = -1;
+
+ Transform3D transform;
};
mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
@@ -193,9 +230,9 @@ private:
struct DecalInstance {
RID decal;
- Transform transform;
- uint32_t render_index;
+ Transform3D transform;
uint32_t cull_mask;
+ ForwardID forward_id = -1;
};
mutable RID_Owner<DecalInstance> decal_instance_owner;
@@ -204,7 +241,7 @@ private:
struct LightmapInstance {
RID lightmap;
- Transform transform;
+ Transform3D transform;
};
mutable RID_Owner<LightmapInstance> lightmap_instance_owner;
@@ -220,7 +257,8 @@ private:
struct ShadowAtlas {
enum {
QUADRANT_SHIFT = 27,
- SHADOW_INDEX_MASK = (1 << QUADRANT_SHIFT) - 1,
+ OMNI_LIGHT_FLAG = 1 << 26,
+ SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1,
SHADOW_INVALID = 0xFFFFFFFF
};
@@ -264,7 +302,9 @@ private:
void _update_shadow_atlas(ShadowAtlas *shadow_atlas);
+ void _shadow_atlas_invalidate_shadow(RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, RendererSceneRenderRD::ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx);
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);
+ bool _shadow_atlas_find_omni_shadows(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::ShadowQuality shadows_quality = RS::SHADOW_QUALITY_MAX; //So it always updates when first set
RS::ShadowQuality directional_shadow_quality = RS::SHADOW_QUALITY_MAX;
@@ -279,6 +319,8 @@ private:
int directional_soft_shadow_samples = 0;
int penumbra_shadow_samples = 0;
int soft_shadow_samples = 0;
+ RS::DecalFilter decals_filter = RS::DECAL_FILTER_LINEAR_MIPMAPS;
+ RS::LightProjectorFilter light_projectors_filter = RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS;
/* DIRECTIONAL SHADOW */
@@ -312,7 +354,7 @@ private:
struct LightInstance {
struct ShadowTransform {
CameraMatrix camera;
- Transform transform;
+ Transform3D transform;
float farplane;
float split;
float bias_scale;
@@ -329,7 +371,7 @@ private:
AABB aabb;
RID self;
RID light;
- Transform transform;
+ Transform3D transform;
Vector3 light_vector;
Vector3 spot_vector;
@@ -339,23 +381,30 @@ private:
uint64_t last_scene_pass = 0;
uint64_t last_scene_shadow_pass = 0;
uint64_t last_pass = 0;
- uint32_t light_index = 0;
uint32_t cull_mask = 0;
uint32_t light_directional_index = 0;
- uint32_t current_shadow_atlas_key = 0;
-
- Vector2 dp;
-
Rect2 directional_rect;
Set<RID> shadow_atlases; //shadow atlases where this light is registered
+ ForwardID forward_id = -1;
+
LightInstance() {}
};
mutable RID_Owner<LightInstance> light_instance_owner;
+ /* FOG VOLUMES */
+
+ struct FogVolumeInstance {
+ RID volume;
+ Transform3D transform;
+ bool active = false;
+ };
+
+ mutable RID_Owner<FogVolumeInstance> fog_volume_instance_owner;
+
/* ENVIRONMENT */
RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
@@ -407,17 +456,26 @@ private:
struct RenderBuffers {
RenderBufferData *data = nullptr;
- int width = 0, height = 0;
+ int internal_width = 0;
+ int internal_height = 0;
+ int width = 0;
+ int height = 0;
+ float fsr_sharpness = 0.2f;
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
bool use_debanding = false;
+ uint32_t view_count = 1;
RID render_target;
uint64_t auto_exposure_version = 1;
- RID texture; //main texture for rendering to, must be filled after done rendering
+ RID sss_texture; //texture for sss. This needs to be a different resolution than blur[0]
+ RID internal_texture; //main texture for rendering to, must be filled after done rendering
+ RID texture; //upscaled version of main texture (This uses the same resource as internal_texture if there is no upscaling)
RID depth_texture; //main depth texture
+ RID texture_fb; // framebuffer for the main texture, ONLY USED FOR MOBILE RENDERER POST EFFECTS, DO NOT USE FOR RENDERING 3D!!!
+ RID upscale_texture; //used when upscaling internal_texture (This uses the same resource as internal_texture if there is no upscaling)
RendererSceneGIRD::SDFGI *sdfgi = nullptr;
VolumetricFog *volumetric_fog = nullptr;
@@ -433,6 +491,11 @@ private:
RID texture;
int width;
int height;
+
+ // only used on mobile renderer
+ RID fb;
+ RID half_texture;
+ RID half_fb;
};
Vector<Mipmap> mipmaps;
@@ -440,9 +503,25 @@ private:
Blur blur[2]; //the second one starts from the first mipmap
+ struct WeightBuffers {
+ RID weight;
+ RID fb; // FB with both texture and weight
+ };
+
+ // 2 full size, 2 half size
+ WeightBuffers weight_buffers[4]; // Only used in raster
+ RID base_weight_fb; // base buffer for weight
+
+ RID depth_back_texture;
+ RID depth_back_fb; // only used on mobile
+
struct Luminance {
Vector<RID> reduce;
RID current;
+
+ // used only on mobile renderer
+ Vector<RID> fb;
+ RID current_fb;
} luminance;
struct SSAO {
@@ -454,6 +533,10 @@ private:
Vector<RID> ao_pong_slices;
RID ao_final;
RID importance_map[2];
+
+ RID downsample_uniform_set;
+ RID gather_uniform_set;
+ RID importance_map_uniform_set;
} ssao;
struct SSR {
@@ -475,10 +558,10 @@ private:
void _free_render_buffer_data(RenderBuffers *rb);
void _allocate_blur_textures(RenderBuffers *rb);
+ void _allocate_depth_backbuffer_textures(RenderBuffers *rb);
void _allocate_luminance_textures(RenderBuffers *rb);
void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
- void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data);
/* Cluster */
@@ -510,7 +593,7 @@ private:
struct LightData {
float position[3];
float inv_radius;
- float direction[3];
+ float direction[3]; // in omni, x and y are used for dual paraboloid offset
float size;
float color[3];
@@ -631,7 +714,7 @@ private:
int render_sdfgi_region_count = 0;
const RendererSceneRender::RenderSDFGIUpdateData *sdfgi_update_data = nullptr;
- uint32_t gi_probe_count = 0;
+ uint32_t voxel_gi_count = 0;
LocalVector<int> cube_shadows;
LocalVector<int> shadows;
@@ -654,45 +737,111 @@ private:
RID light_density_map;
RID prev_light_density_map;
-
RID fog_map;
- RID uniform_set;
- RID uniform_set2;
+ RID density_map;
+ RID light_map;
+ RID emissive_map;
+
+ RID fog_uniform_set;
+ RID copy_uniform_set;
+ RID process_uniform_set;
+ RID process_uniform_set2;
RID sdfgi_uniform_set;
RID sky_uniform_set;
int last_shadow_filter = -1;
- Transform prev_cam_transform;
- };
-
- enum {
- VOLUMETRIC_FOG_SHADER_DENSITY,
- VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI,
- VOLUMETRIC_FOG_SHADER_FILTER,
- VOLUMETRIC_FOG_SHADER_FOG,
- VOLUMETRIC_FOG_SHADER_MAX,
+ Transform3D prev_cam_transform;
};
struct VolumetricFogShader {
- struct ParamsUBO {
+ enum FogSet {
+ FOG_SET_BASE,
+ FOG_SET_UNIFORMS,
+ FOG_SET_MATERIAL,
+ FOG_SET_MAX,
+ };
+
+ struct FogPushConstant {
+ float position[3];
+ float pad;
+
+ float extents[3];
+ float pad2;
+
+ int32_t corner[3];
+ uint32_t shape;
+
+ float transform[16];
+ };
+
+ struct VolumeUBO {
float fog_frustum_size_begin[2];
float fog_frustum_size_end[2];
float fog_frustum_end;
float z_near;
float z_far;
+ float time;
+
+ int32_t fog_volume_size[3];
+ uint32_t directional_light_count;
+
+ uint32_t use_temporal_reprojection;
+ uint32_t temporal_frame;
+ float detail_spread;
+ float temporal_blend;
+
+ float to_prev_view[16];
+ float transform[16];
+ };
+
+ ShaderCompilerRD compiler;
+ VolumetricFogShaderRD shader;
+ FogPushConstant push_constant;
+ RID volume_ubo;
+
+ RID default_shader;
+ RID default_material;
+ RID default_shader_rd;
+
+ RID base_uniform_set;
+
+ RID params_ubo;
+
+ enum {
+ VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY,
+ VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI,
+ VOLUMETRIC_FOG_PROCESS_SHADER_FILTER,
+ VOLUMETRIC_FOG_PROCESS_SHADER_FOG,
+ VOLUMETRIC_FOG_PROCESS_SHADER_COPY,
+ VOLUMETRIC_FOG_PROCESS_SHADER_MAX,
+ };
+
+ struct ParamsUBO {
+ float fog_frustum_size_begin[2];
+ float fog_frustum_size_end[2];
+
+ float fog_frustum_end;
+ float ambient_inject;
+ float z_far;
uint32_t filter_axis;
+ float ambient_color[3];
+ float sky_contribution;
+
int32_t fog_volume_size[3];
uint32_t directional_light_count;
- float light_energy[3];
+ float base_emission[3];
float base_density;
+ float base_scattering[3];
+ float phase_g;
+
float detail_spread;
float gi_inject;
- uint32_t max_gi_probes;
+ uint32_t max_voxel_gi_instances;
uint32_t cluster_type_size;
float screen_size[2];
@@ -706,13 +855,13 @@ private:
float cam_rotation[12];
float to_prev_view[16];
+ float radiance_inverse_xform[12];
};
- VolumetricFogShaderRD shader;
+ VolumetricFogProcessShaderRD process_shader;
- RID params_ubo;
- RID shader_version;
- RID pipelines[VOLUMETRIC_FOG_SHADER_MAX];
+ RID process_shader_version;
+ RID process_pipelines[VOLUMETRIC_FOG_PROCESS_SHADER_MAX];
} volumetric_fog;
@@ -720,8 +869,57 @@ private:
uint32_t volumetric_fog_size = 128;
bool volumetric_fog_filter_active = true;
+ Vector3i _point_get_position_in_froxel_volume(const Vector3 &p_point, float fog_end, const Vector2 &fog_near_size, const Vector2 &fog_far_size, float volumetric_fog_detail_spread, const Vector3 &fog_size, const Transform3D &p_cam_transform);
void _volumetric_fog_erase(RenderBuffers *rb);
- void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count);
+ void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform3D &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes);
+
+ struct FogShaderData : public RendererStorageRD::ShaderData {
+ bool valid;
+ RID version;
+
+ RID pipeline;
+ Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String path;
+ String code;
+ Map<StringName, Map<int, RID>> default_texture_params;
+
+ bool uses_time;
+
+ virtual void set_code(const String &p_Code);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
+ virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
+ virtual bool is_param_texture(const StringName &p_param) const;
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+ FogShaderData();
+ virtual ~FogShaderData();
+ };
+
+ struct FogMaterialData : public RendererStorageRD::MaterialData {
+ uint64_t last_frame;
+ FogShaderData *shader_data;
+ RID uniform_set;
+ bool uniform_set_updated;
+
+ virtual void set_render_priority(int p_priority) {}
+ virtual void set_next_pass(RID p_pass) {}
+ virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual ~FogMaterialData();
+ };
+
+ RendererStorageRD::ShaderData *_create_fog_shader_func();
+ static RendererStorageRD::ShaderData *_create_fog_shader_funcs();
+
+ RendererStorageRD::MaterialData *_create_fog_material_func(FogShaderData *p_shader);
+ static RendererStorageRD::MaterialData *_create_fog_material_funcs(RendererStorageRD::ShaderData *p_shader);
RID shadow_sampler;
@@ -737,39 +935,39 @@ private:
uint32_t max_cluster_elements = 512;
- void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true);
+ void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RendererScene::RenderInfo *p_render_info = nullptr);
public:
- virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance) = 0;
+ virtual Transform3D geometry_instance_get_transform(GeometryInstance *p_instance) = 0;
virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance) = 0;
/* SHADOW ATLAS API */
- RID shadow_atlas_create();
- void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false);
- void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision);
- bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version);
+ virtual RID shadow_atlas_create() override;
+ virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false) override;
+ virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
+ virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override;
_FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) {
- ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas);
+ ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
ERR_FAIL_COND_V(!atlas, false);
return atlas->shadow_owners.has(p_light_intance);
}
_FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) {
- ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas);
+ ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
ERR_FAIL_COND_V(!atlas, RID());
return atlas->depth;
}
_FORCE_INLINE_ Size2i shadow_atlas_get_size(RID p_atlas) {
- ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas);
+ ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
ERR_FAIL_COND_V(!atlas, Size2i());
return Size2(atlas->size, atlas->size);
}
- void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false);
- int get_directional_light_shadow_size(RID p_light_intance);
- void set_directional_shadow_count(int p_count);
+ virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) override;
+ virtual int get_directional_light_shadow_size(RID p_light_intance) override;
+ virtual void set_directional_shadow_count(int p_count) override;
_FORCE_INLINE_ RID directional_shadow_get_texture() {
return directional_shadow.depth;
@@ -781,57 +979,56 @@ public:
/* SDFGI UPDATE */
- virtual void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position);
- virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const;
- virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const;
- virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const;
+ virtual void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) override;
+ virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const override;
+ virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const override;
+ virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const override;
RID sdfgi_get_ubo() const { return gi.sdfgi_ubo; }
/* SKY API */
- virtual RID sky_allocate();
- virtual void sky_initialize(RID p_rid);
+ virtual RID sky_allocate() override;
+ virtual void sky_initialize(RID p_rid) override;
- void sky_set_radiance_size(RID p_sky, int p_radiance_size);
- void sky_set_mode(RID p_sky, RS::SkyMode p_mode);
- void sky_set_material(RID p_sky, RID p_material);
- Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size);
+ virtual void sky_set_radiance_size(RID p_sky, int p_radiance_size) override;
+ virtual void sky_set_mode(RID p_sky, RS::SkyMode p_mode) override;
+ virtual void sky_set_material(RID p_sky, RID p_material) override;
+ virtual Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) override;
/* ENVIRONMENT API */
- virtual RID environment_allocate();
- virtual void environment_initialize(RID p_rid);
+ virtual RID environment_allocate() override;
+ virtual void environment_initialize(RID p_rid) override;
- void environment_set_background(RID p_env, RS::EnvironmentBG p_bg);
- void environment_set_sky(RID p_env, RID p_sky);
- void environment_set_sky_custom_fov(RID p_env, float p_scale);
- void environment_set_sky_orientation(RID p_env, const Basis &p_orientation);
- void environment_set_bg_color(RID p_env, const Color &p_color);
- void environment_set_bg_energy(RID p_env, float p_energy);
- void environment_set_canvas_max_layer(RID p_env, int p_max_layer);
- void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color());
+ virtual void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) override;
+ virtual void environment_set_sky(RID p_env, RID p_sky) override;
+ virtual void environment_set_sky_custom_fov(RID p_env, float p_scale) override;
+ virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) override;
+ virtual void environment_set_bg_color(RID p_env, const Color &p_color) override;
+ virtual void environment_set_bg_energy(RID p_env, float p_energy) override;
+ virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) override;
+ virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) override;
- RS::EnvironmentBG environment_get_background(RID p_env) const;
+ virtual RS::EnvironmentBG environment_get_background(RID p_env) const override;
RID environment_get_sky(RID p_env) const;
float environment_get_sky_custom_fov(RID p_env) const;
Basis environment_get_sky_orientation(RID p_env) const;
Color environment_get_bg_color(RID p_env) const;
float environment_get_bg_energy(RID p_env) const;
- int environment_get_canvas_max_layer(RID p_env) const;
+ virtual int environment_get_canvas_max_layer(RID p_env) const override;
Color environment_get_ambient_light_color(RID p_env) const;
RS::EnvironmentAmbientSource environment_get_ambient_source(RID p_env) const;
float environment_get_ambient_light_energy(RID p_env) const;
float environment_get_ambient_sky_contribution(RID p_env) const;
RS::EnvironmentReflectionSource environment_get_reflection_source(RID p_env) const;
- Color environment_get_ao_color(RID p_env) const;
- bool is_environment(RID p_env) const;
+ virtual bool is_environment(RID p_env) const override;
- void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap);
- void environment_glow_set_use_bicubic_upscale(bool p_enable);
- void environment_glow_set_use_high_quality(bool p_enable);
+ virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) override;
+ virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) override;
+ virtual void environment_glow_set_use_high_quality(bool p_enable) override;
- void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective);
+ virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) override;
bool environment_is_fog_enabled(RID p_env) const;
Color environment_get_fog_light_color(RID p_env) const;
float environment_get_fog_light_energy(RID p_env) const;
@@ -841,61 +1038,71 @@ public:
float environment_get_fog_height_density(RID p_env) const;
float environment_get_fog_aerial_perspective(RID p_env) const;
- void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount);
+ virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) override;
- virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth);
- virtual void environment_set_volumetric_fog_filter_active(bool p_enable);
+ virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) override;
+ virtual void environment_set_volumetric_fog_filter_active(bool p_enable) override;
- void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance);
- void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect);
- void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to);
+ virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) override;
+ virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) override;
+ virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override;
bool environment_is_ssao_enabled(RID p_env) const;
float environment_get_ssao_ao_affect(RID p_env) const;
float environment_get_ssao_light_affect(RID p_env) const;
bool environment_is_ssr_enabled(RID p_env) const;
bool environment_is_sdfgi_enabled(RID p_env) const;
- virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias);
- virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count);
- virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames);
- virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update);
+ virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) override;
+ virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) override;
+ virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) override;
+ virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) override;
- void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality);
+ virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override;
RS::EnvironmentSSRRoughnessQuality environment_get_ssr_roughness_quality() const;
- void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale);
- void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction);
+ virtual void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) override;
+ virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) override;
- virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size);
+ virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override;
+
+ /* CAMERA EFFECTS */
- virtual RID camera_effects_allocate();
- virtual void camera_effects_initialize(RID p_rid);
+ virtual RID camera_effects_allocate() override;
+ virtual void camera_effects_initialize(RID p_rid) override;
- virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter);
- virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape);
+ virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) override;
+ virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) override;
- 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);
- virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure);
+ 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) override;
+ virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) override;
+
+ bool camera_effects_uses_dof(RID p_camera_effects) {
+ CameraEffects *camfx = camera_effects_owner.get_or_null(p_camera_effects);
+
+ return camfx && (camfx->dof_blur_near_enabled || camfx->dof_blur_far_enabled) && camfx->dof_blur_amount > 0.0;
+ }
- RID light_instance_create(RID p_light);
- void light_instance_set_transform(RID p_light_instance, const Transform &p_transform);
- void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb);
- 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);
+ /* LIGHT INSTANCE API */
+
+ virtual RID light_instance_create(RID p_light) override;
+ virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override;
+ virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override;
+ virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &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()) override;
+ virtual void light_instance_mark_visible(RID p_light_instance) override;
_FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
return li->light;
}
- _FORCE_INLINE_ Transform light_instance_get_base_transform(RID p_light_instance) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ _FORCE_INLINE_ Transform3D light_instance_get_base_transform(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
return li->transform;
}
- _FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas) {
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ _FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas, Vector2i &r_omni_offset) {
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
uint32_t key = shadow_atlas->shadow_owners[li->self];
uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
@@ -913,6 +1120,16 @@ public:
x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+ if (key & ShadowAtlas::OMNI_LIGHT_FLAG) {
+ if (((shadow + 1) % shadow_atlas->quadrants[quadrant].subdivision) == 0) {
+ r_omni_offset.x = 1 - int(shadow_atlas->quadrants[quadrant].subdivision);
+ r_omni_offset.y = 1;
+ } else {
+ r_omni_offset.x = 1;
+ r_omni_offset.y = 0;
+ }
+ }
+
uint32_t width = shadow_size;
uint32_t height = shadow_size;
@@ -920,16 +1137,16 @@ public:
}
_FORCE_INLINE_ CameraMatrix light_instance_get_shadow_camera(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
return li->shadow_transform[p_index].camera;
}
_FORCE_INLINE_ float light_instance_get_shadow_texel_size(RID p_light_instance, RID p_shadow_atlas) {
#ifdef DEBUG_ENABLED
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0);
#endif
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
ERR_FAIL_COND_V(!shadow_atlas, 0);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0);
@@ -945,186 +1162,192 @@ public:
return float(1.0) / shadow_size;
}
- _FORCE_INLINE_ Transform
+ _FORCE_INLINE_ Transform3D
light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
return li->shadow_transform[p_index].transform;
}
_FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
return li->shadow_transform[p_index].bias_scale;
}
_FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ LightInstance *li = light_instance_owner.get_or_null(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);
+ LightInstance *li = light_instance_owner.get_or_null(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);
+ LightInstance *li = light_instance_owner.get_or_null(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) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
return li->shadow_transform[p_index].atlas_rect;
}
_FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
return li->shadow_transform[p_index].split;
}
_FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
return li->shadow_transform[p_index].shadow_texel_size;
}
_FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
li->last_pass = p_pass;
}
_FORCE_INLINE_ uint64_t light_instance_get_render_pass(RID p_light_instance) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
return li->last_pass;
}
- _FORCE_INLINE_ void light_instance_set_index(RID p_light_instance, uint32_t p_index) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- li->light_index = p_index;
- }
-
- _FORCE_INLINE_ uint32_t light_instance_get_index(RID p_light_instance) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- return li->light_index;
+ _FORCE_INLINE_ ForwardID light_instance_get_forward_id(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->forward_id;
}
_FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
return li->light_type;
}
- virtual RID reflection_atlas_create();
- virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count);
- virtual int reflection_atlas_get_size(RID p_ref_atlas) const;
+ /* FOG VOLUMES */
+
+ virtual RID fog_volume_instance_create(RID p_fog_volume) override;
+ virtual void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override;
+ virtual void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override;
+ virtual RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override;
+ virtual Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override;
+
+ virtual RID reflection_atlas_create() override;
+ virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override;
+ virtual int reflection_atlas_get_size(RID p_ref_atlas) const override;
_FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) {
- ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_ref_atlas);
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_ref_atlas);
ERR_FAIL_COND_V(!atlas, RID());
return atlas->reflection;
}
- virtual RID reflection_probe_instance_create(RID p_probe);
- virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform);
- virtual void reflection_probe_release_atlas_index(RID p_instance);
- virtual bool reflection_probe_instance_needs_redraw(RID p_instance);
- virtual bool reflection_probe_instance_has_reflection(RID p_instance);
- virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas);
- virtual bool reflection_probe_instance_postprocess_step(RID p_instance);
+ virtual RID reflection_probe_instance_create(RID p_probe) override;
+ virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override;
+ virtual void reflection_probe_release_atlas_index(RID p_instance) override;
+ virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override;
+ virtual bool reflection_probe_instance_has_reflection(RID p_instance) override;
+ virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
+ virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth);
+ virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override;
uint32_t reflection_probe_instance_get_resolution(RID p_instance);
RID reflection_probe_instance_get_framebuffer(RID p_instance, int p_index);
RID reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index);
_FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!rpi, RID());
return rpi->probe;
}
- _FORCE_INLINE_ void reflection_probe_instance_set_render_index(RID p_instance, uint32_t p_render_index) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!rpi);
- rpi->render_index = p_render_index;
- }
-
- _FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_index(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ _FORCE_INLINE_ ForwardID reflection_probe_instance_get_forward_id(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!rpi, 0);
- return rpi->render_index;
+ return rpi->forward_id;
}
_FORCE_INLINE_ void reflection_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!rpi);
rpi->last_pass = p_render_pass;
}
_FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_pass(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!rpi, 0);
return rpi->last_pass;
}
- _FORCE_INLINE_ Transform reflection_probe_instance_get_transform(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!rpi, Transform());
+ _FORCE_INLINE_ Transform3D reflection_probe_instance_get_transform(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND_V(!rpi, Transform3D());
return rpi->transform;
}
_FORCE_INLINE_ int reflection_probe_instance_get_atlas_index(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!rpi, -1);
return rpi->atlas_index;
}
- virtual RID decal_instance_create(RID p_decal);
- virtual void decal_instance_set_transform(RID p_decal, const Transform &p_transform);
+ virtual RID decal_instance_create(RID p_decal) override;
+ virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override;
_FORCE_INLINE_ RID decal_instance_get_base(RID p_decal) const {
- DecalInstance *decal = decal_instance_owner.getornull(p_decal);
+ DecalInstance *decal = decal_instance_owner.get_or_null(p_decal);
return decal->decal;
}
- _FORCE_INLINE_ Transform decal_instance_get_transform(RID p_decal) const {
- DecalInstance *decal = decal_instance_owner.getornull(p_decal);
+ _FORCE_INLINE_ ForwardID decal_instance_get_forward_id(RID p_decal) const {
+ DecalInstance *decal = decal_instance_owner.get_or_null(p_decal);
+ return decal->forward_id;
+ }
+
+ _FORCE_INLINE_ Transform3D decal_instance_get_transform(RID p_decal) const {
+ DecalInstance *decal = decal_instance_owner.get_or_null(p_decal);
return decal->transform;
}
- virtual RID lightmap_instance_create(RID p_lightmap);
- virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform);
+ virtual RID lightmap_instance_create(RID p_lightmap) override;
+ virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
_FORCE_INLINE_ bool lightmap_instance_is_valid(RID p_lightmap_instance) {
- return lightmap_instance_owner.getornull(p_lightmap_instance) != nullptr;
+ return lightmap_instance_owner.get_or_null(p_lightmap_instance) != nullptr;
}
_FORCE_INLINE_ RID lightmap_instance_get_lightmap(RID p_lightmap_instance) {
- LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap_instance);
+ LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance);
return li->lightmap;
}
- _FORCE_INLINE_ Transform lightmap_instance_get_transform(RID p_lightmap_instance) {
- LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap_instance);
+ _FORCE_INLINE_ Transform3D lightmap_instance_get_transform(RID p_lightmap_instance) {
+ LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance);
return li->transform;
}
- void _fill_instance_indices(const RID *p_omni_light_instances, uint32_t p_omni_light_instance_count, uint32_t *p_omni_light_indices, const RID *p_spot_light_instances, uint32_t p_spot_light_instance_count, uint32_t *p_spot_light_indices, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count, uint32_t *p_reflection_probe_indices, const RID *p_decal_instances, uint32_t p_decal_instance_count, uint32_t *p_decal_instance_indices, uint32_t p_layer_mask, uint32_t p_max_dst_words = 2);
-
/* gi light probes */
- RID gi_probe_instance_create(RID p_base);
- void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);
- bool gi_probe_needs_update(RID p_probe) const;
- void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects);
- void gi_probe_set_quality(RS::GIProbeQuality p_quality) { gi.gi_probe_quality = p_quality; }
+ virtual RID voxel_gi_instance_create(RID p_base) override;
+ virtual void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) override;
+ virtual bool voxel_gi_needs_update(RID p_probe) const override;
+ virtual void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects) override;
+ virtual void voxel_gi_set_quality(RS::VoxelGIQuality p_quality) override { gi.voxel_gi_quality = p_quality; }
/* render buffers */
- 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, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding);
- void gi_set_use_half_resolution(bool p_enable);
+ virtual float _render_buffers_get_luminance_multiplier();
+ virtual RD::DataFormat _render_buffers_get_color_format();
+ virtual bool _render_buffers_can_be_storage();
+ virtual RID render_buffers_create() override;
+ virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override;
+ virtual void gi_set_use_half_resolution(bool p_enable) override;
+ RID render_buffers_get_depth_texture(RID p_render_buffers);
RID render_buffers_get_ao_texture(RID p_render_buffers);
RID render_buffers_get_back_buffer_texture(RID p_render_buffers);
- RID render_buffers_get_gi_probe_buffer(RID p_render_buffers);
- RID render_buffers_get_default_gi_probe_buffer();
+ RID render_buffers_get_back_depth_texture(RID p_render_buffers);
+ RID render_buffers_get_voxel_gi_buffer(RID p_render_buffers);
+ RID render_buffers_get_default_voxel_gi_buffer();
RID render_buffers_get_gi_ambient_texture(RID p_render_buffers);
RID render_buffers_get_gi_reflection_texture(RID p_render_buffers);
@@ -1147,30 +1370,36 @@ public:
float render_buffers_get_volumetric_fog_end(RID p_render_buffers);
float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers);
- void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr);
+ virtual void update_uniform_sets(){};
+
+ virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override;
- void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
+ virtual void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
- void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances);
+ virtual void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) override;
- virtual void set_scene_pass(uint64_t p_pass) {
+ virtual void set_scene_pass(uint64_t p_pass) override {
scene_pass = p_pass;
}
_FORCE_INLINE_ uint64_t get_scene_pass() {
return scene_pass;
}
- virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit);
- virtual bool screen_space_roughness_limiter_is_active() const;
+ virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) override;
+ virtual bool screen_space_roughness_limiter_is_active() const override;
virtual float screen_space_roughness_limiter_get_amount() const;
virtual float screen_space_roughness_limiter_get_limit() const;
- virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality);
+ virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override;
RS::SubSurfaceScatteringQuality sub_surface_scattering_get_quality() const;
- virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale);
+ virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override;
+
+ virtual void shadows_quality_set(RS::ShadowQuality p_quality) override;
+ virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) override;
+
+ virtual void decals_set_filter(RS::DecalFilter p_filter) override;
+ virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) override;
- 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; }
@@ -1186,21 +1415,24 @@ public:
_FORCE_INLINE_ int penumbra_shadow_samples_get() const { return penumbra_shadow_samples; }
_FORCE_INLINE_ int soft_shadow_samples_get() const { return soft_shadow_samples; }
+ _FORCE_INLINE_ RS::LightProjectorFilter light_projectors_get_filter() const { return light_projectors_filter; }
+ _FORCE_INLINE_ RS::DecalFilter decals_get_filter() const { return decals_filter; }
+
int get_roughness_layers() const;
bool is_using_radiance_cubemap_array() const;
- virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size);
+ virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) override;
- virtual bool free(RID p_rid);
+ virtual bool free(RID p_rid) override;
- virtual void update();
+ virtual void update() override;
- virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw);
+ virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override;
_FORCE_INLINE_ RS::ViewportDebugDraw get_debug_draw_mode() const {
return debug_draw;
}
- void set_time(double p_time, double p_step);
+ virtual void set_time(double p_time, double p_step) override;
RID get_reflection_probe_buffer();
RID get_omni_light_buffer();
@@ -1209,13 +1441,15 @@ public:
RID get_decal_buffer();
int get_max_directional_lights() const;
- void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir);
+ virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override;
virtual bool is_dynamic_gi_supported() const;
virtual bool is_clustered_enabled() const;
virtual bool is_volumetric_supported() const;
virtual uint32_t get_max_elements() const;
+ void init();
+
RendererSceneRenderRD(RendererStorageRD *p_storage);
~RendererSceneRenderRD();
};
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
index 54c6e81110..a9c39fb937 100644
--- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
@@ -30,7 +30,9 @@
#include "renderer_scene_sky_rd.h"
#include "core/config/project_settings.h"
+#include "core/math/math_defs.h"
#include "renderer_scene_render_rd.h"
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/rendering_server_default.h"
////////////////////////////////////////////////////////////////////////////////
@@ -90,8 +92,7 @@ void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) {
RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
Error err = scene_singleton->sky.sky_shader.compiler.compile(RS::SHADER_SKY, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = scene_singleton->sky.sky_shader.shader.version_create();
@@ -125,54 +126,67 @@ void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) {
depth_stencil_state.enable_depth_test = true;
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
- RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i);
- pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0);
+ if (scene_singleton->sky.sky_shader.shader.is_variant_enabled(i)) {
+ RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i);
+ pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0);
+ } else {
+ pipelines[i].clear();
+ }
}
valid = true;
}
-void RendererSceneSkyRD::SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+void RendererSceneSkyRD::SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
- default_texture_params.erase(p_name);
+ if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
+ default_texture_params[p_name].erase(p_index);
+
+ if (default_texture_params[p_name].is_empty()) {
+ default_texture_params.erase(p_name);
+ }
+ }
} else {
- default_texture_params[p_name] = p_texture;
+ if (!default_texture_params.has(p_name)) {
+ default_texture_params[p_name] = Map<int, RID>();
+ }
+ default_texture_params[p_name][p_index] = p_texture;
}
}
void RendererSceneSkyRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
Map<int, StringName> order;
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
- if (E->get().texture_order >= 0) {
- order[E->get().texture_order + 100000] = E->key();
+ if (E.value.texture_order >= 0) {
+ order[E.value.texture_order + 100000] = E.key;
} else {
- order[E->get().order] = E->key();
+ order[E.value.order] = E.key;
}
}
- for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
- pi.name = E->get();
+ for (const KeyValue<int, StringName> &E : order) {
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
+ pi.name = E.value;
p_param_list->push_back(pi);
}
}
void RendererSceneSkyRD::SkyShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
RendererStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E->get());
- p.info.name = E->key(); //supply name
- p.index = E->get().instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+ p.info = ShaderLanguage::uniform_to_property_info(E.value);
+ p.info.name = E.key; //supply name
+ p.index = E.value.instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
p_param_list->push_back(p);
}
}
@@ -197,7 +211,7 @@ Variant RendererSceneSkyRD::SkyShaderData::get_default_parameter(const StringNam
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
return Variant();
}
@@ -224,96 +238,82 @@ RendererSceneSkyRD::SkyShaderData::~SkyShaderData() {
////////////////////////////////////////////////////////////////////////////////
// Sky material
-void RendererSceneSkyRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+bool RendererSceneSkyRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
uniform_set_updated = true;
- if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
- p_uniform_dirty = true;
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- uniform_buffer = RID();
- }
-
- ubo_data.resize(shader_data->ubo_size);
- if (ubo_data.size()) {
- uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
- memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
- }
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL);
+}
- //check whether buffer changed
- if (p_uniform_dirty && ubo_data.size()) {
- update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
- RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw());
- }
+RendererSceneSkyRD::SkyMaterialData::~SkyMaterialData() {
+ free_parameters_uniform_set(uniform_set);
+}
- uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
+////////////////////////////////////////////////////////////////////////////////
+// Render sky
+
+static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_array) {
+ p_array[0] = p_basis.elements[0][0];
+ p_array[1] = p_basis.elements[1][0];
+ p_array[2] = p_basis.elements[2][0];
+ p_array[3] = 0;
+ p_array[4] = p_basis.elements[0][1];
+ p_array[5] = p_basis.elements[1][1];
+ p_array[6] = p_basis.elements[2][1];
+ p_array[7] = 0;
+ p_array[8] = p_basis.elements[0][2];
+ p_array[9] = p_basis.elements[1][2];
+ p_array[10] = p_basis.elements[2][2];
+ p_array[11] = 0;
+}
- if ((uint32_t)texture_cache.size() != tex_uniform_count) {
- texture_cache.resize(tex_uniform_count);
- p_textures_dirty = true;
+void RendererSceneSkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const CameraMatrix *p_projections, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position, float p_luminance_multiplier) {
+ SkyPushConstant sky_push_constant;
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
+ memset(&sky_push_constant, 0, sizeof(SkyPushConstant));
- if (p_textures_dirty && tex_uniform_count) {
- update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true);
+ for (uint32_t v = 0; v < p_view_count; v++) {
+ // We only need key components of our projection matrix
+ sky_push_constant.projections[v][0] = p_projections[v].matrix[2][0];
+ sky_push_constant.projections[v][1] = p_projections[v].matrix[0][0];
+ sky_push_constant.projections[v][2] = p_projections[v].matrix[2][1];
+ sky_push_constant.projections[v][3] = p_projections[v].matrix[1][1];
}
+ sky_push_constant.position[0] = p_position.x;
+ sky_push_constant.position[1] = p_position.y;
+ sky_push_constant.position[2] = p_position.z;
+ sky_push_constant.multiplier = p_multiplier;
+ sky_push_constant.time = p_time;
+ sky_push_constant.luminance_multiplier = p_luminance_multiplier;
+ store_transform_3x3(p_orientation, sky_push_constant.orientation);
- if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) {
- // This material does not require an uniform set, so don't create it.
- return;
- }
+ RenderingDevice::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_fb);
- if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- //no reason to update uniform set, only UBO (or nothing) was needed to update
- return;
- }
+ RD::DrawListID draw_list = p_list;
- Vector<RD::Uniform> uniforms;
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, p_pipeline->get_render_pipeline(RD::INVALID_ID, fb_format, false, RD::get_singleton()->draw_list_get_current_pass()));
+ // Update uniform sets.
{
- if (shader_data->ubo_size) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 0;
- u.ids.push_back(uniform_buffer);
- uniforms.push_back(u);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.uniform_set, 0);
+ if (p_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(p_uniform_set)) { // Material may not have a uniform set.
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1);
}
-
- const RID *textures = texture_cache.ptrw();
- for (uint32_t i = 0; i < tex_uniform_count; i++) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1 + i;
- u.ids.push_back(textures[i]);
- uniforms.push_back(u);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2);
+ // Fog uniform set can be invalidated before drawing, so validate at draw time
+ if (sky_scene_state.fog_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.fog_uniform_set)) {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.fog_uniform_set, 3);
+ } else {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.default_fog_uniform_set, 3);
}
}
- uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL);
-}
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
-RendererSceneSkyRD::SkyMaterialData::~SkyMaterialData() {
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- }
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &sky_push_constant, sizeof(SkyPushConstant));
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- }
+ RD::get_singleton()->draw_list_draw(draw_list, true);
}
////////////////////////////////////////////////////////////////////////////////
@@ -330,12 +330,16 @@ void RendererSceneSkyRD::ReflectionData::clear_reflection_data() {
coefficient_buffer = RID();
}
-void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers) {
+void RendererSceneSkyRD::ReflectionData::update_reflection_data(RendererStorageRD *p_storage, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format) {
//recreate radiance and all data
int mipmaps = p_mipmaps;
uint32_t w = p_size, h = p_size;
+ EffectsRD *effects = p_storage->get_effects();
+ ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
+ bool prefer_raster_effects = effects->get_prefer_raster_effects();
+
if (p_use_array) {
int num_layers = p_low_quality ? 8 : p_roughness_layers;
@@ -394,9 +398,9 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int
}
radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP);
-
+ RD::get_singleton()->set_resource_name(radiance_base_cubemap, "radiance base cubemap");
RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.format = p_texture_format;
tf.width = 64; // Always 64x64
tf.height = 64;
tf.texture_type = RD::TEXTURE_TYPE_CUBE;
@@ -405,6 +409,7 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
downsampled_radiance_cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ RD::get_singleton()->set_resource_name(downsampled_radiance_cubemap, "downsampled radiance cubemap");
{
uint32_t mmw = 64;
uint32_t mmh = 64;
@@ -414,6 +419,18 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int
mm.size.width = mmw;
mm.size.height = mmh;
mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, RD::TEXTURE_SLICE_CUBEMAP);
+ RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip " + itos(j) + " ");
+ if (prefer_raster_effects) {
+ // we need a framebuffer for each side of our cubemap
+
+ for (int k = 0; k < 6; k++) {
+ mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, k, j);
+ RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip: " + itos(j) + " Face: " + itos(k) + " ");
+ Vector<RID> fbtex;
+ fbtex.push_back(mm.views[k]);
+ mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex);
+ }
+ }
mmw = MAX(1, mmw >> 1);
mmh = MAX(1, mmh >> 1);
@@ -422,50 +439,128 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int
}
void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays) {
- p_storage->get_effects()->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size);
+ EffectsRD *effects = p_storage->get_effects();
+ ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
+ bool prefer_raster_effects = effects->get_prefer_raster_effects();
+
+ if (prefer_raster_effects) {
+ RD::get_singleton()->draw_command_begin_label("Downsample radiance map");
+ for (int k = 0; k < 6; k++) {
+ effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size);
+ }
- for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
- p_storage->get_effects()->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size);
- }
+ for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
+ for (int k = 0; k < 6; k++) {
+ effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size);
+ }
+ }
+ RD::get_singleton()->draw_command_end_label(); // Downsample Radiance
- Vector<RID> views;
- if (p_use_arrays) {
- for (int i = 1; i < layers.size(); i++) {
- views.push_back(layers[i].views[0]);
+ if (p_use_arrays) {
+ RD::get_singleton()->draw_command_begin_label("filter radiance map into array heads");
+ for (int i = 0; i < layers.size(); i++) {
+ for (int k = 0; k < 6; k++) {
+ effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[i].mipmaps[0].framebuffers[k], k, i);
+ }
+ }
+ } else {
+ RD::get_singleton()->draw_command_begin_label("filter radiance map into mipmaps directly");
+ for (int j = 0; j < layers[0].mipmaps.size(); j++) {
+ for (int k = 0; k < 6; k++) {
+ effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[0].mipmaps[j].framebuffers[k], k, j);
+ }
+ }
}
+ RD::get_singleton()->draw_command_end_label(); // Filter radiance
} else {
- for (int i = 1; i < layers[0].views.size(); i++) {
- views.push_back(layers[0].views[i]);
+ effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size);
+
+ for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
+ effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size);
}
- }
- p_storage->get_effects()->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays);
+ Vector<RID> views;
+ if (p_use_arrays) {
+ for (int i = 1; i < layers.size(); i++) {
+ views.push_back(layers[i].views[0]);
+ }
+ } else {
+ for (int i = 1; i < layers[0].views.size(); i++) {
+ views.push_back(layers[0].views[i]);
+ }
+ }
+
+ effects->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays);
+ }
}
void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality) {
- if (p_use_arrays) {
- //render directly to the layers
- p_storage->get_effects()->cubemap_roughness(radiance_base_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x);
+ EffectsRD *effects = p_storage->get_effects();
+ ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
+ bool prefer_raster_effects = effects->get_prefer_raster_effects();
+
+ if (prefer_raster_effects) {
+ // Need to ask clayjohn but p_cube_side is set to 10, looks like in the compute shader we're doing all 6 sides in one call
+ // here we need to do them one by one so ignoring p_cube_side
+ if (p_use_arrays) {
+ for (int k = 0; k < 6; k++) {
+ effects->cubemap_roughness_raster(
+ radiance_base_cubemap,
+ layers[p_base_layer].mipmaps[0].framebuffers[k],
+ k,
+ p_sky_ggx_samples_quality,
+ float(p_base_layer) / (layers.size() - 1.0),
+ layers[p_base_layer].mipmaps[0].size.x);
+ }
+ } else {
+ for (int k = 0; k < 6; k++) {
+ effects->cubemap_roughness_raster(
+ layers[0].views[p_base_layer - 1],
+ layers[0].mipmaps[p_base_layer].framebuffers[k],
+ k,
+ p_sky_ggx_samples_quality,
+ float(p_base_layer) / (layers[0].mipmaps.size() - 1.0),
+ layers[0].mipmaps[p_base_layer].size.x);
+ }
+ }
} else {
- p_storage->get_effects()->cubemap_roughness(
- layers[0].views[p_base_layer - 1],
- layers[0].views[p_base_layer],
- p_cube_side,
- p_sky_ggx_samples_quality,
- float(p_base_layer) / (layers[0].mipmaps.size() - 1.0),
- layers[0].mipmaps[p_base_layer].size.x);
+ if (p_use_arrays) {
+ //render directly to the layers
+ effects->cubemap_roughness(radiance_base_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x);
+ } else {
+ effects->cubemap_roughness(
+ layers[0].views[p_base_layer - 1],
+ layers[0].views[p_base_layer],
+ p_cube_side,
+ p_sky_ggx_samples_quality,
+ float(p_base_layer) / (layers[0].mipmaps.size() - 1.0),
+ layers[0].mipmaps[p_base_layer].size.x);
+ }
}
}
void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end) {
+ EffectsRD *effects = p_storage->get_effects();
+ ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
+ bool prefer_raster_effects = effects->get_prefer_raster_effects();
+
+ RD::get_singleton()->draw_command_begin_label("Update Radiance Cubemap Array Mipmaps");
for (int i = p_start; i < p_end; i++) {
for (int j = 0; j < layers[i].views.size() - 1; j++) {
RID view = layers[i].views[j];
- RID texture = layers[i].views[j + 1];
Size2i size = layers[i].mipmaps[j + 1].size;
- p_storage->get_effects()->cubemap_downsample(view, texture, size);
+ if (prefer_raster_effects) {
+ for (int k = 0; k < 6; k++) {
+ RID framebuffer = layers[i].mipmaps[j + 1].framebuffers[k];
+ effects->cubemap_downsample_raster(view, framebuffer, k, size);
+ }
+ } else {
+ RID texture = layers[i].views[j + 1];
+ effects->cubemap_downsample(view, texture, size);
+ }
}
}
+ RD::get_singleton()->draw_command_end_label();
}
////////////////////////////////////////////////////////////////////////////////
@@ -622,7 +717,7 @@ Ref<Image> RendererSceneSkyRD::Sky::bake_panorama(RendererStorageRD *p_storage,
RD::get_singleton()->free(rad_tex);
Ref<Image> img;
- img.instance();
+ img.instantiate();
img->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF, data);
for (int i = 0; i < p_size.width; i++) {
for (int j = 0; j < p_size.height; j++) {
@@ -693,7 +788,18 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n"); // Cubemap
sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_HALF_RES_PASS\n"); // Half Res Cubemap
sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_QUARTER_RES_PASS\n"); // Quarter res Cubemap
+
+ sky_modes.push_back("\n#define USE_MULTIVIEW\n"); // Full size multiview
+ sky_modes.push_back("\n#define USE_HALF_RES_PASS\n#define USE_MULTIVIEW\n"); // Half Res multiview
+ sky_modes.push_back("\n#define USE_QUARTER_RES_PASS\n#define USE_MULTIVIEW\n"); // Quarter res multiview
+
sky_shader.shader.initialize(sky_modes, defines);
+
+ if (!RendererCompositorRD::singleton->is_xr_enabled()) {
+ sky_shader.shader.set_variant_enabled(SKY_VERSION_BACKGROUND_MULTIVIEW, false);
+ sky_shader.shader.set_variant_enabled(SKY_VERSION_HALF_RES_MULTIVIEW, false);
+ sky_shader.shader.set_variant_enabled(SKY_VERSION_QUARTER_RES_MULTIVIEW, false);
+ }
}
// register our shader funds
@@ -710,6 +816,9 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
actions.renames["SKY_COORDS"] = "panorama_coords";
actions.renames["SCREEN_UV"] = "uv";
actions.renames["TIME"] = "params.time";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
actions.renames["HALF_RES_COLOR"] = "half_res_color";
actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color";
actions.renames["RADIANCE"] = "radiance";
@@ -760,7 +869,15 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
sky_shader.default_shader = storage->shader_allocate();
storage->shader_initialize(sky_shader.default_shader);
- storage->shader_set_code(sky_shader.default_shader, "shader_type sky; void sky() { COLOR = vec3(0.0); } \n");
+ storage->shader_set_code(sky_shader.default_shader, R"(
+// Default sky shader.
+
+shader_type sky;
+
+void sky() {
+ COLOR = vec3(0.0);
+}
+)");
sky_shader.default_material = storage->material_allocate();
storage->material_initialize(sky_shader.default_material);
@@ -841,7 +958,17 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
sky_scene_state.fog_shader = storage->shader_allocate();
storage->shader_initialize(sky_scene_state.fog_shader);
- storage->shader_set_code(sky_scene_state.fog_shader, "shader_type sky; uniform vec4 clear_color; void sky() { COLOR = clear_color.rgb; } \n");
+ storage->shader_set_code(sky_scene_state.fog_shader, R"(
+// Default clear color sky shader.
+
+shader_type sky;
+
+uniform vec4 clear_color;
+
+void sky() {
+ COLOR = clear_color.rgb;
+}
+)");
sky_scene_state.fog_material = storage->material_allocate();
storage->material_initialize(sky_scene_state.fog_material);
@@ -872,9 +999,48 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES);
}
+
+ { //create index array for copy shaders
+ Vector<uint8_t> pv;
+ pv.resize(6 * 4);
+ {
+ uint8_t *w = pv.ptrw();
+ int *p32 = (int *)w;
+ p32[0] = 0;
+ p32[1] = 1;
+ p32[2] = 2;
+ p32[3] = 0;
+ p32[4] = 2;
+ p32[5] = 3;
+ }
+ index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv);
+ index_array = RD::get_singleton()->index_array_create(index_buffer, 0, 6);
+ }
}
-void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) {
+void RendererSceneSkyRD::set_texture_format(RD::DataFormat p_texture_format) {
+ texture_format = p_texture_format;
+}
+
+RendererSceneSkyRD::~RendererSceneSkyRD() {
+ // TODO cleanup anything created in init...
+
+ if (RD::get_singleton()->uniform_set_is_valid(sky_scene_state.uniform_set)) {
+ RD::get_singleton()->free(sky_scene_state.uniform_set);
+ }
+
+ if (RD::get_singleton()->uniform_set_is_valid(sky_scene_state.default_fog_uniform_set)) {
+ RD::get_singleton()->free(sky_scene_state.default_fog_uniform_set);
+ }
+
+ if (RD::get_singleton()->uniform_set_is_valid(sky_scene_state.fog_only_texture_uniform_set)) {
+ RD::get_singleton()->free(sky_scene_state.fog_only_texture_uniform_set);
+ }
+
+ RD::get_singleton()->free(index_buffer); //array gets freed as dependency
+}
+
+void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) {
ERR_FAIL_COND(!p_env); // I guess without an environment we also can't have a sky...
SkyMaterialData *material = nullptr;
@@ -884,11 +1050,7 @@ void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_b
SkyShaderData *shader_data = nullptr;
- RS::EnvironmentBG background = p_env->background;
-
- if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
- // !BAS! Possibly silently fail here, we now get error spam when you select sky as the background but haven't setup the sky yet.
- ERR_FAIL_COND(!sky);
+ if (sky) {
sky_material = sky_get_material(p_env->sky);
if (sky_material.is_valid()) {
@@ -908,9 +1070,7 @@ void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_b
shader_data = material->shader_data;
ERR_FAIL_COND(!shader_data);
- }
- if (sky) {
// Invalidate supbass buffers if screen size changes
if (sky->screen_size != p_screen_size) {
sky->screen_size = p_screen_size;
@@ -1019,14 +1179,8 @@ void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_b
} else {
sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0;
}
- }
-
- RID fog_uniform_set = p_scene_render->render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers);
- if (fog_uniform_set != RID()) {
- sky_scene_state.fog_uniform_set = fog_uniform_set;
- } else {
- sky_scene_state.fog_uniform_set = sky_scene_state.default_fog_uniform_set;
+ sky_scene_state.fog_uniform_set = p_scene_render->render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers);
}
}
@@ -1044,7 +1198,7 @@ void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_b
RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo);
}
-void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform &p_transform, double p_time) {
+void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) {
ERR_FAIL_COND(!p_env);
Sky *sky = get_sky(p_env->sky);
@@ -1124,6 +1278,7 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
cm = correction * cm;
if (shader_data->uses_quarter_res) {
+ RD::get_singleton()->draw_command_begin_label("Render Sky to Quarter Res Cubemap");
PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES];
Vector<Color> clear_colors;
@@ -1131,17 +1286,18 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
RD::DrawListID cubemap_draw_list;
for (int i = 0; i < 6; i++) {
- Transform local_view;
- local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
+ Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
+ RD::get_singleton()->draw_command_end_label();
}
if (shader_data->uses_half_res) {
+ RD::get_singleton()->draw_command_begin_label("Render Sky to Half Res Cubemap");
PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES];
Vector<Color> clear_colors;
@@ -1149,28 +1305,29 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
RD::DrawListID cubemap_draw_list;
for (int i = 0; i < 6; i++) {
- Transform local_view;
- local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
+ Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
+ RD::get_singleton()->draw_command_end_label();
}
RD::DrawListID cubemap_draw_list;
PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP];
+ RD::get_singleton()->draw_command_begin_label("Render Sky Cubemap");
for (int i = 0; i < 6; i++) {
- Transform local_view;
- local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
+ Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
+ RD::get_singleton()->draw_command_end_label();
if (sky_mode == RS::SKY_MODE_REALTIME) {
sky->reflection.create_reflection_fast_filter(storage, sky_use_cubemap_array);
@@ -1209,11 +1366,13 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
}
}
-void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, const CameraMatrix &p_projection, const Transform &p_transform, double p_time) {
+void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time) {
ERR_FAIL_COND(!p_env);
+ ERR_FAIL_COND(p_view_count == 0);
+ ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
+
Sky *sky = get_sky(p_env->sky);
- ERR_FAIL_COND(!sky);
SkyMaterialData *material = nullptr;
RID sky_material;
@@ -1253,24 +1412,28 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont
float multiplier = p_env->bg_energy;
float custom_fov = p_env->sky_custom_fov;
+
// Camera
CameraMatrix camera;
+ uint32_t view_count = p_view_count;
+ const CameraMatrix *projections = p_projections;
if (custom_fov) {
- float near_plane = p_projection.get_z_near();
- float far_plane = p_projection.get_z_far();
- float aspect = p_projection.get_aspect();
+ // With custom fov we don't support stereo...
+ float near_plane = p_projections[0].get_z_near();
+ float far_plane = p_projections[0].get_z_far();
+ float aspect = p_projections[0].get_aspect();
camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
- } else {
- camera = p_projection;
+ view_count = 1;
+ projections = &camera;
}
sky_transform = p_transform.basis * sky_transform;
if (shader_data->uses_quarter_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_QUARTER_RES];
+ PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES];
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd);
@@ -1278,12 +1441,12 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont
clear_colors.push_back(Color(0.0, 0.0, 0.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- storage->get_effects()->render_sky(draw_list, p_time, sky->quarter_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, 1.0);
RD::get_singleton()->draw_list_end();
}
if (shader_data->uses_half_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_HALF_RES];
+ PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES];
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd);
@@ -1291,11 +1454,11 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont
clear_colors.push_back(Color(0.0, 0.0, 0.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- storage->get_effects()->render_sky(draw_list, p_time, sky->half_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, 1.0);
RD::get_singleton()->draw_list_end();
}
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND];
+ PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND];
RID texture_uniform_set;
if (sky) {
@@ -1305,10 +1468,172 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont
}
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
- storage->get_effects()->render_sky(draw_list, p_time, p_fb, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ _render_sky(draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, 1.0);
RD::get_singleton()->draw_list_end();
}
+void RendererSceneSkyRD::update_res_buffers(RendererSceneEnvironmentRD *p_env, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) {
+ ERR_FAIL_COND(!p_env);
+
+ ERR_FAIL_COND(p_view_count == 0);
+ ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
+
+ Sky *sky = get_sky(p_env->sky);
+ ERR_FAIL_COND(!sky);
+
+ SkyMaterialData *material = nullptr;
+ RID sky_material;
+
+ sky_material = sky_get_material(p_env->sky);
+
+ if (sky_material.is_valid()) {
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+
+ ERR_FAIL_COND(!material);
+
+ SkyShaderData *shader_data = material->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ Basis sky_transform = p_env->sky_orientation;
+ sky_transform.invert();
+
+ float multiplier = p_env->bg_energy;
+ float custom_fov = p_env->sky_custom_fov;
+
+ // Camera
+ CameraMatrix camera;
+ uint32_t view_count = p_view_count;
+ const CameraMatrix *projections = p_projections;
+
+ if (custom_fov) {
+ // With custom fov we don't support stereo...
+ float near_plane = p_projections[0].get_z_near();
+ float far_plane = p_projections[0].get_z_far();
+ float aspect = p_projections[0].get_aspect();
+
+ camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
+
+ view_count = 1;
+ projections = &camera;
+ }
+
+ sky_transform = p_transform.basis * sky_transform;
+
+ if (shader_data->uses_quarter_res) {
+ PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES];
+
+ RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd);
+
+ Vector<Color> clear_colors;
+ clear_colors.push_back(Color(0.0, 0.0, 0.0));
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
+ _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, p_luminance_multiplier);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ if (shader_data->uses_half_res) {
+ PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES];
+
+ RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd);
+
+ Vector<Color> clear_colors;
+ clear_colors.push_back(Color(0.0, 0.0, 0.0));
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
+ _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, p_luminance_multiplier);
+ RD::get_singleton()->draw_list_end();
+ }
+}
+
+void RendererSceneSkyRD::draw(RD::DrawListID p_draw_list, RendererSceneEnvironmentRD *p_env, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) {
+ ERR_FAIL_COND(!p_env);
+
+ ERR_FAIL_COND(p_view_count == 0);
+ ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
+
+ Sky *sky = get_sky(p_env->sky);
+
+ SkyMaterialData *material = nullptr;
+ RID sky_material;
+
+ RS::EnvironmentBG background = p_env->background;
+
+ if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+ ERR_FAIL_COND(!sky);
+ sky_material = sky_get_material(p_env->sky);
+
+ if (sky_material.is_valid()) {
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+ }
+
+ if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+ sky_material = sky_scene_state.fog_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+
+ ERR_FAIL_COND(!material);
+
+ SkyShaderData *shader_data = material->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ Basis sky_transform = p_env->sky_orientation;
+ sky_transform.invert();
+
+ float multiplier = p_env->bg_energy;
+ float custom_fov = p_env->sky_custom_fov;
+
+ // Camera
+ CameraMatrix camera;
+ uint32_t view_count = p_view_count;
+ const CameraMatrix *projections = p_projections;
+
+ if (custom_fov) {
+ // With custom fov we don't support stereo...
+ float near_plane = p_projections[0].get_z_near();
+ float far_plane = p_projections[0].get_z_far();
+ float aspect = p_projections[0].get_aspect();
+
+ camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
+
+ view_count = 1;
+ projections = &camera;
+ }
+
+ sky_transform = p_transform.basis * sky_transform;
+
+ PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND];
+
+ RID texture_uniform_set;
+ if (sky) {
+ texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd);
+ } else {
+ texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
+ }
+
+ _render_sky(p_draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, p_luminance_multiplier);
+}
+
void RendererSceneSkyRD::invalidate_sky(Sky *p_sky) {
if (!p_sky->dirty) {
p_sky->dirty = true;
@@ -1340,7 +1665,7 @@ void RendererSceneSkyRD::update_dirty_skys() {
//array (higher quality, 6 times more memory)
RD::TextureFormat tf;
tf.array_layers = layers * 6;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.format = texture_format;
tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
tf.mipmaps = mipmaps;
tf.width = w;
@@ -1349,13 +1674,13 @@ void RendererSceneSkyRD::update_dirty_skys() {
sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
- sky->reflection.update_reflection_data(sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers);
+ sky->reflection.update_reflection_data(storage, sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format);
} else {
//regular cubemap, lower quality (aliasing, less memory)
RD::TextureFormat tf;
tf.array_layers = 6;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.format = texture_format;
tf.texture_type = RD::TEXTURE_TYPE_CUBE;
tf.mipmaps = MIN(mipmaps, layers);
tf.width = w;
@@ -1364,7 +1689,7 @@ void RendererSceneSkyRD::update_dirty_skys() {
sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
- sky->reflection.update_reflection_data(sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers);
+ sky->reflection.update_reflection_data(storage, sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format);
}
texture_set_dirty = true;
}
@@ -1372,7 +1697,7 @@ void RendererSceneSkyRD::update_dirty_skys() {
// Create subpass buffers if they haven't been created already
if (sky->half_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->half_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
RD::TextureFormat tformat;
- tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tformat.format = texture_format;
tformat.width = sky->screen_size.x / 2;
tformat.height = sky->screen_size.y / 2;
tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
@@ -1387,7 +1712,7 @@ void RendererSceneSkyRD::update_dirty_skys() {
if (sky->quarter_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->quarter_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
RD::TextureFormat tformat;
- tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tformat.format = texture_format;
tformat.width = sky->screen_size.x / 4;
tformat.height = sky->screen_size.y / 4;
tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
@@ -1437,7 +1762,7 @@ void RendererSceneSkyRD::initialize_sky_rid(RID p_rid) {
}
RendererSceneSkyRD::Sky *RendererSceneSkyRD::get_sky(RID p_sky) const {
- return sky_owner.getornull(p_sky);
+ return sky_owner.get_or_null(p_sky);
}
void RendererSceneSkyRD::free_sky(RID p_sky) {
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h
index 73390a586b..8689395bea 100644
--- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h
@@ -43,9 +43,6 @@
class RendererSceneRenderRD;
class RendererSceneSkyRD {
-private:
- RendererStorageRD *storage;
-
public:
enum SkySet {
SKY_SET_UNIFORMS,
@@ -55,6 +52,23 @@ public:
SKY_SET_MAX
};
+ // Skys need less info from Directional Lights than the normal shaders
+ struct SkyDirectionalLightData {
+ float direction[3];
+ float energy;
+ float color[3];
+ float size;
+ uint32_t enabled;
+ uint32_t pad[3];
+ };
+
+private:
+ RendererStorageRD *storage;
+ RD::DataFormat texture_format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+
+ RID index_buffer;
+ RID index_array;
+
enum SkyTextureSetVersion {
SKY_TEXTURE_SET_BACKGROUND,
SKY_TEXTURE_SET_HALF_RES,
@@ -72,19 +86,62 @@ public:
SKY_VERSION_CUBEMAP,
SKY_VERSION_CUBEMAP_HALF_RES,
SKY_VERSION_CUBEMAP_QUARTER_RES,
+
+ SKY_VERSION_BACKGROUND_MULTIVIEW,
+ SKY_VERSION_HALF_RES_MULTIVIEW,
+ SKY_VERSION_QUARTER_RES_MULTIVIEW,
+
SKY_VERSION_MAX
};
- // Skys need less info from Directional Lights than the normal shaders
- struct SkyDirectionalLightData {
- float direction[3];
- float energy;
- float color[3];
- float size;
- uint32_t enabled;
- uint32_t pad[3];
+ struct SkyPushConstant {
+ float orientation[12]; // 48 - 48
+ float projections[RendererSceneRender::MAX_RENDER_VIEWS][4]; // 2 x 16 - 80
+ float position[3]; // 12 - 92
+ float multiplier; // 4 - 96
+ float time; // 4 - 100
+ float luminance_multiplier; // 4 - 104
+ float pad[2]; // 8 - 112 // Using pad to align on 16 bytes
+ // 128 is the max size of a push constant. We can replace "pad" but we can't add any more.
};
+ struct SkyShaderData : public RendererStorageRD::ShaderData {
+ bool valid;
+ RID version;
+
+ PipelineCacheRD pipelines[SKY_VERSION_MAX];
+ Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String path;
+ String code;
+ Map<StringName, Map<int, RID>> default_texture_params;
+
+ bool uses_time;
+ bool uses_position;
+ bool uses_half_res;
+ bool uses_quarter_res;
+ bool uses_light;
+
+ virtual void set_code(const String &p_Code);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
+ virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
+ virtual bool is_param_texture(const StringName &p_param) const;
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+ SkyShaderData();
+ virtual ~SkyShaderData();
+ };
+
+ void _render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const CameraMatrix *p_projections, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position, float p_luminance_multiplier);
+
+public:
struct SkySceneState {
struct UBO {
uint32_t volumetric_fog_enabled;
@@ -135,6 +192,10 @@ public:
struct Mipmap {
RID view;
Size2i size;
+
+ // for mobile only
+ RID views[6];
+ RID framebuffers[6];
};
Vector<Mipmap> mipmaps;
};
@@ -149,46 +210,12 @@ public:
Vector<Layer> layers;
void clear_reflection_data();
- void update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers);
+ void update_reflection_data(RendererStorageRD *p_storage, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format);
void create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays);
void create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality);
void update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end);
};
- struct SkyShaderData : public RendererStorageRD::ShaderData {
- bool valid;
- RID version;
-
- PipelineCacheRD pipelines[SKY_VERSION_MAX];
- Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
- Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
-
- Vector<uint32_t> ubo_offsets;
- uint32_t ubo_size;
-
- String path;
- String code;
- Map<StringName, RID> default_texture_params;
-
- bool uses_time;
- bool uses_position;
- bool uses_half_res;
- bool uses_quarter_res;
- bool uses_light;
-
- virtual void set_code(const String &p_Code);
- virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
- virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
- virtual bool is_param_texture(const StringName &p_param) const;
- virtual bool is_animated() const;
- virtual bool casts_shadows() const;
- virtual Variant get_default_parameter(const StringName &p_parameter) const;
- virtual RS::ShaderNativeSourceCode get_native_source_code() const;
- SkyShaderData();
- virtual ~SkyShaderData();
- };
-
/* Sky shader */
struct SkyShader {
@@ -203,15 +230,12 @@ public:
struct SkyMaterialData : public RendererStorageRD::MaterialData {
uint64_t last_frame;
SkyShaderData *shader_data;
- RID uniform_buffer;
RID uniform_set;
- Vector<RID> texture_cache;
- Vector<uint8_t> ubo_data;
bool uniform_set_updated;
virtual void set_render_priority(int p_priority) {}
virtual void set_next_pass(RID p_pass) {}
- virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual ~SkyMaterialData();
};
@@ -265,12 +289,15 @@ public:
static RendererStorageRD::MaterialData *_create_sky_material_funcs(RendererStorageRD::ShaderData *p_shader);
RendererSceneSkyRD();
-
void init(RendererStorageRD *p_storage);
-
- void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
- void update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform &p_transform, double p_time);
- void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, const CameraMatrix &p_projection, const Transform &p_transform, double p_time);
+ void set_texture_format(RD::DataFormat p_texture_format);
+ ~RendererSceneSkyRD();
+
+ void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
+ void update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0);
+ void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time); // only called by clustered renderer
+ void update_res_buffers(RendererSceneEnvironmentRD *p_env, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0);
+ void draw(RD::DrawListID p_draw_list, RendererSceneEnvironmentRD *p_env, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0);
void invalidate_sky(Sky *p_sky);
void update_dirty_skys();
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index f419875d58..29e4a63cbb 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -33,7 +33,9 @@
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/io/resource_loader.h"
+#include "core/math/math_defs.h"
#include "renderer_compositor_rd.h"
+#include "servers/rendering/rendering_server_globals.h"
#include "servers/rendering/shader_language.h"
bool RendererStorageRD::can_create_resources_async() const {
@@ -840,7 +842,7 @@ void RendererStorageRD::texture_3d_initialize(RID p_texture, Image::Format p_for
}
void RendererStorageRD::texture_proxy_initialize(RID p_texture, RID p_base) {
- Texture *tex = texture_owner.getornull(p_base);
+ Texture *tex = texture_owner.get_or_null(p_base);
ERR_FAIL_COND(!tex);
Texture proxy_tex = *tex;
@@ -863,7 +865,7 @@ void RendererStorageRD::texture_proxy_initialize(RID p_texture, RID p_base) {
void RendererStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate) {
ERR_FAIL_COND(p_image.is_null() || p_image->is_empty());
- Texture *tex = texture_owner.getornull(p_texture);
+ Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND(!tex);
ERR_FAIL_COND(tex->is_render_target);
ERR_FAIL_COND(p_image->get_width() != tex->width || p_image->get_height() != tex->height);
@@ -882,16 +884,12 @@ void RendererStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_im
RD::get_singleton()->texture_update(tex->rd_texture, p_layer, validated->get_data());
}
-void RendererStorageRD::texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer) {
- _texture_2d_update(p_texture, p_image, p_layer, true);
-}
-
void RendererStorageRD::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) {
_texture_2d_update(p_texture, p_image, p_layer, false);
}
void RendererStorageRD::texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) {
- Texture *tex = texture_owner.getornull(p_texture);
+ Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND(!tex);
ERR_FAIL_COND(tex->type != Texture::TYPE_3D);
Image::Image3DValidateError verr = Image::validate_3d_image(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps > 1, p_data);
@@ -928,10 +926,10 @@ void RendererStorageRD::texture_3d_update(RID p_texture, const Vector<Ref<Image>
}
void RendererStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) {
- Texture *tex = texture_owner.getornull(p_texture);
+ Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND(!tex);
ERR_FAIL_COND(!tex->is_proxy);
- Texture *proxy_to = texture_owner.getornull(p_proxy_to);
+ Texture *proxy_to = texture_owner.get_or_null(p_proxy_to);
ERR_FAIL_COND(!proxy_to);
ERR_FAIL_COND(proxy_to->is_proxy);
@@ -945,7 +943,7 @@ void RendererStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) {
RD::get_singleton()->free(tex->rd_texture_srgb);
tex->rd_texture_srgb = RID();
}
- Texture *prev_tex = texture_owner.getornull(tex->proxy_to);
+ Texture *prev_tex = texture_owner.get_or_null(tex->proxy_to);
ERR_FAIL_COND(!prev_tex);
prev_tex->proxies.erase(p_texture);
}
@@ -971,7 +969,7 @@ void RendererStorageRD::texture_2d_placeholder_initialize(RID p_texture) {
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
Ref<Image> image;
- image.instance();
+ image.instantiate();
image->create(4, 4, false, Image::FORMAT_RGBA8);
for (int i = 0; i < 4; i++) {
@@ -987,7 +985,7 @@ void RendererStorageRD::texture_2d_layered_placeholder_initialize(RID p_texture,
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
Ref<Image> image;
- image.instance();
+ image.instantiate();
image->create(4, 4, false, Image::FORMAT_RGBA8);
for (int i = 0; i < 4; i++) {
@@ -1013,7 +1011,7 @@ void RendererStorageRD::texture_3d_placeholder_initialize(RID p_texture) {
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
Ref<Image> image;
- image.instance();
+ image.instantiate();
image->create(4, 4, false, Image::FORMAT_RGBA8);
for (int i = 0; i < 4; i++) {
@@ -1032,18 +1030,18 @@ void RendererStorageRD::texture_3d_placeholder_initialize(RID p_texture) {
}
Ref<Image> RendererStorageRD::texture_2d_get(RID p_texture) const {
- Texture *tex = texture_owner.getornull(p_texture);
+ Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND_V(!tex, Ref<Image>());
#ifdef TOOLS_ENABLED
- if (tex->image_cache_2d.is_valid()) {
+ if (tex->image_cache_2d.is_valid() && !tex->is_render_target) {
return tex->image_cache_2d;
}
#endif
Vector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0);
ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
Ref<Image> image;
- image.instance();
+ image.instantiate();
image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data);
ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
if (tex->format != tex->validated_format) {
@@ -1051,7 +1049,7 @@ Ref<Image> RendererStorageRD::texture_2d_get(RID p_texture) const {
}
#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
+ if (Engine::get_singleton()->is_editor_hint() && !tex->is_render_target) {
tex->image_cache_2d = image;
}
#endif
@@ -1060,13 +1058,13 @@ Ref<Image> RendererStorageRD::texture_2d_get(RID p_texture) const {
}
Ref<Image> RendererStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) const {
- Texture *tex = texture_owner.getornull(p_texture);
+ Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND_V(!tex, Ref<Image>());
Vector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, p_layer);
ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
Ref<Image> image;
- image.instance();
+ image.instantiate();
image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data);
ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
if (tex->format != tex->validated_format) {
@@ -1077,7 +1075,7 @@ Ref<Image> RendererStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) c
}
Vector<Ref<Image>> RendererStorageRD::texture_3d_get(RID p_texture) const {
- Texture *tex = texture_owner.getornull(p_texture);
+ Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND_V(!tex, Vector<Ref<Image>>());
ERR_FAIL_COND_V(tex->type != Texture::TYPE_3D, Vector<Ref<Image>>());
@@ -1094,7 +1092,7 @@ Vector<Ref<Image>> RendererStorageRD::texture_3d_get(RID p_texture) const {
Vector<uint8_t> sub_region = all_data.subarray(bs.offset, bs.offset + bs.buffer_size - 1);
Ref<Image> img;
- img.instance();
+ img.instantiate();
img->create(bs.size.width, bs.size.height, false, tex->validated_format, sub_region);
ERR_FAIL_COND_V(img->is_empty(), Vector<Ref<Image>>());
if (tex->format != tex->validated_format) {
@@ -1108,10 +1106,10 @@ Vector<Ref<Image>> RendererStorageRD::texture_3d_get(RID p_texture) const {
}
void RendererStorageRD::texture_replace(RID p_texture, RID p_by_texture) {
- Texture *tex = texture_owner.getornull(p_texture);
+ Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND(!tex);
ERR_FAIL_COND(tex->proxy_to.is_valid()); //can't replace proxy
- Texture *by_tex = texture_owner.getornull(p_by_texture);
+ Texture *by_tex = texture_owner.get_or_null(p_by_texture);
ERR_FAIL_COND(!by_tex);
ERR_FAIL_COND(by_tex->proxy_to.is_valid()); //can't replace proxy
@@ -1157,7 +1155,7 @@ void RendererStorageRD::texture_replace(RID p_texture, RID p_by_texture) {
}
void RendererStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) {
- Texture *tex = texture_owner.getornull(p_texture);
+ Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND(!tex);
ERR_FAIL_COND(tex->type != Texture::TYPE_2D);
tex->width_2d = p_width;
@@ -1165,7 +1163,7 @@ void RendererStorageRD::texture_set_size_override(RID p_texture, int p_width, in
}
void RendererStorageRD::texture_set_path(RID p_texture, const String &p_path) {
- Texture *tex = texture_owner.getornull(p_texture);
+ Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND(!tex);
tex->path = p_path;
}
@@ -1175,21 +1173,21 @@ String RendererStorageRD::texture_get_path(RID p_texture) const {
}
void RendererStorageRD::texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
- Texture *tex = texture_owner.getornull(p_texture);
+ Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND(!tex);
tex->detect_3d_callback_ud = p_userdata;
tex->detect_3d_callback = p_callback;
}
void RendererStorageRD::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
- Texture *tex = texture_owner.getornull(p_texture);
+ Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND(!tex);
tex->detect_normal_callback_ud = p_userdata;
tex->detect_normal_callback = p_callback;
}
void RendererStorageRD::texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) {
- Texture *tex = texture_owner.getornull(p_texture);
+ Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND(!tex);
tex->detect_roughness_callback_ud = p_userdata;
tex->detect_roughness_callback = p_callback;
@@ -1229,15 +1227,109 @@ RendererStorageRD::CanvasTexture::~CanvasTexture() {
clear_sets();
}
+void RendererStorageRD::sampler_rd_configure_custom(float p_mipmap_bias) {
+ for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
+ for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
+ RD::SamplerState sampler_state;
+ switch (i) {
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.max_lod = 0;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.max_lod = 0;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
+ sampler_state.lod_bias = p_mipmap_bias;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
+ sampler_state.lod_bias = p_mipmap_bias;
+
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
+ sampler_state.lod_bias = p_mipmap_bias;
+ sampler_state.use_anisotropy = true;
+ sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
+ } 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;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
+ sampler_state.lod_bias = p_mipmap_bias;
+ sampler_state.use_anisotropy = true;
+ sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
+
+ } break;
+ default: {
+ }
+ }
+ switch (j) {
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT;
+ sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_REPEAT;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+ sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+ } break;
+ default: {
+ }
+ }
+
+ if (custom_rd_samplers[i][j].is_valid()) {
+ RD::get_singleton()->free(custom_rd_samplers[i][j]);
+ }
+
+ custom_rd_samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state);
+ }
+ }
+}
+
RID RendererStorageRD::canvas_texture_allocate() {
return canvas_texture_owner.allocate_rid();
}
void RendererStorageRD::canvas_texture_initialize(RID p_rid) {
- canvas_texture_owner.initialize_rid(p_rid, memnew(CanvasTexture));
+ canvas_texture_owner.initialize_rid(p_rid);
}
void RendererStorageRD::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) {
- CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture);
+ CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture);
switch (p_channel) {
case RS::CANVAS_TEXTURE_CHANNEL_DIFFUSE: {
ct->diffuse = p_texture;
@@ -1254,7 +1346,7 @@ void RendererStorageRD::canvas_texture_set_channel(RID p_canvas_texture, RS::Can
}
void RendererStorageRD::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) {
- CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture);
+ CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture);
ct->specular_color.r = p_specular_color.r;
ct->specular_color.g = p_specular_color.g;
ct->specular_color.b = p_specular_color.b;
@@ -1263,13 +1355,13 @@ void RendererStorageRD::canvas_texture_set_shading_parameters(RID p_canvas_textu
}
void RendererStorageRD::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) {
- CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture);
+ CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture);
ct->texture_filter = p_filter;
ct->clear_sets();
}
void RendererStorageRD::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) {
- CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture);
+ CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture);
ct->texture_repeat = p_repeat;
ct->clear_sets();
}
@@ -1277,7 +1369,7 @@ void RendererStorageRD::canvas_texture_set_texture_repeat(RID p_canvas_texture,
bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular) {
CanvasTexture *ct = nullptr;
- Texture *t = texture_owner.getornull(p_texture);
+ Texture *t = texture_owner.get_or_null(p_texture);
if (t) {
//regular texture
@@ -1288,7 +1380,7 @@ bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canvas
ct = t->canvas_texture;
} else {
- ct = canvas_texture_owner.getornull(p_texture);
+ ct = canvas_texture_owner.get_or_null(p_texture);
}
if (!ct) {
@@ -1310,7 +1402,7 @@ bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canvas
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 0;
- t = texture_owner.getornull(ct->diffuse);
+ t = texture_owner.get_or_null(ct->diffuse);
if (!t) {
u.ids.push_back(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE));
ct->size_cache = Size2i(1, 1);
@@ -1325,7 +1417,7 @@ bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canvas
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
- t = texture_owner.getornull(ct->normal_map);
+ t = texture_owner.get_or_null(ct->normal_map);
if (!t) {
u.ids.push_back(texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL));
ct->use_normal_cache = false;
@@ -1340,7 +1432,7 @@ bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canvas
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 2;
- t = texture_owner.getornull(ct->specular);
+ t = texture_owner.get_or_null(ct->specular);
if (!t) {
u.ids.push_back(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE));
ct->use_specular_cache = false;
@@ -1386,7 +1478,7 @@ void RendererStorageRD::shader_initialize(RID p_rid) {
}
void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) {
- Shader *shader = shader_owner.getornull(p_shader);
+ Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND(!shader);
shader->code = p_code;
@@ -1401,6 +1493,8 @@ void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) {
new_type = SHADER_TYPE_3D;
} else if (mode_string == "sky") {
new_type = SHADER_TYPE_SKY;
+ } else if (mode_string == "fog") {
+ new_type = SHADER_TYPE_FOG;
} else {
new_type = SHADER_TYPE_MAX;
}
@@ -1439,8 +1533,12 @@ void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) {
material->shader_type = new_type;
}
- for (Map<StringName, RID>::Element *E = shader->default_texture_parameter.front(); E; E = E->next()) {
- shader->data->set_default_texture_param(E->key(), E->get());
+ if (shader->data) {
+ for (const KeyValue<StringName, Map<int, RID>> &E : shader->default_texture_parameter) {
+ for (const KeyValue<int, RID> &E2 : E.value) {
+ shader->data->set_default_texture_param(E.key, E2.value, E2.key);
+ }
+ }
}
}
@@ -1456,30 +1554,39 @@ void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) {
}
String RendererStorageRD::shader_get_code(RID p_shader) const {
- Shader *shader = shader_owner.getornull(p_shader);
+ Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND_V(!shader, String());
return shader->code;
}
void RendererStorageRD::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
- Shader *shader = shader_owner.getornull(p_shader);
+ Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND(!shader);
if (shader->data) {
return shader->data->get_param_list(p_param_list);
}
}
-void RendererStorageRD::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) {
- Shader *shader = shader_owner.getornull(p_shader);
+void RendererStorageRD::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) {
+ Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND(!shader);
if (p_texture.is_valid() && texture_owner.owns(p_texture)) {
- shader->default_texture_parameter[p_name] = p_texture;
+ if (!shader->default_texture_parameter.has(p_name)) {
+ shader->default_texture_parameter[p_name] = Map<int, RID>();
+ }
+ shader->default_texture_parameter[p_name][p_index] = p_texture;
} else {
- shader->default_texture_parameter.erase(p_name);
+ if (shader->default_texture_parameter.has(p_name) && shader->default_texture_parameter[p_name].has(p_index)) {
+ shader->default_texture_parameter[p_name].erase(p_index);
+
+ if (shader->default_texture_parameter[p_name].is_empty()) {
+ shader->default_texture_parameter.erase(p_name);
+ }
+ }
}
if (shader->data) {
- shader->data->set_default_texture_param(p_name, p_texture);
+ shader->data->set_default_texture_param(p_name, p_texture, p_index);
}
for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
Material *material = E->get();
@@ -1487,18 +1594,18 @@ void RendererStorageRD::shader_set_default_texture_param(RID p_shader, const Str
}
}
-RID RendererStorageRD::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const {
- Shader *shader = shader_owner.getornull(p_shader);
+RID RendererStorageRD::shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const {
+ Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND_V(!shader, RID());
- if (shader->default_texture_parameter.has(p_name)) {
- return shader->default_texture_parameter[p_name];
+ if (shader->default_texture_parameter.has(p_name) && shader->default_texture_parameter[p_name].has(p_index)) {
+ return shader->default_texture_parameter[p_name][p_index];
}
return RID();
}
Variant RendererStorageRD::shader_get_param_default(RID p_shader, const StringName &p_param) const {
- Shader *shader = shader_owner.getornull(p_shader);
+ Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND_V(!shader, Variant());
if (shader->data) {
return shader->data->get_default_parameter(p_param);
@@ -1512,7 +1619,7 @@ void RendererStorageRD::shader_set_data_request_function(ShaderType p_shader_typ
}
RS::ShaderNativeSourceCode RendererStorageRD::shader_get_native_source_code(RID p_shader) const {
- Shader *shader = shader_owner.getornull(p_shader);
+ Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND_V(!shader, RS::ShaderNativeSourceCode());
if (shader->data) {
return shader->data->get_native_source_code();
@@ -1526,33 +1633,24 @@ RID RendererStorageRD::material_allocate() {
return material_owner.allocate_rid();
}
void RendererStorageRD::material_initialize(RID p_rid) {
- Material material;
- material.data = nullptr;
- material.shader = nullptr;
- material.shader_type = SHADER_TYPE_MAX;
- material.update_next = nullptr;
- material.update_requested = false;
- material.uniform_dirty = false;
- material.texture_dirty = false;
- material.priority = 0;
- material.self = p_rid;
- material_owner.initialize_rid(p_rid, material);
+ material_owner.initialize_rid(p_rid);
+ Material *material = material_owner.get_or_null(p_rid);
+ material->self = p_rid;
}
void RendererStorageRD::_material_queue_update(Material *material, bool p_uniform, bool p_texture) {
- if (material->update_requested) {
+ if (material->update_element.in_list()) {
return;
}
- material->update_next = material_update_list;
- material_update_list = material;
- material->update_requested = true;
+ material_update_list.add(&material->update_element);
+
material->uniform_dirty = material->uniform_dirty || p_uniform;
material->texture_dirty = material->texture_dirty || p_texture;
}
void RendererStorageRD::material_set_shader(RID p_material, RID p_shader) {
- Material *material = material_owner.getornull(p_material);
+ Material *material = material_owner.get_or_null(p_material);
ERR_FAIL_COND(!material);
if (material->data) {
@@ -1572,7 +1670,7 @@ void RendererStorageRD::material_set_shader(RID p_material, RID p_shader) {
return;
}
- Shader *shader = shader_owner.getornull(p_shader);
+ Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND(!shader);
material->shader = shader;
material->shader_type = shader->type;
@@ -1595,12 +1693,13 @@ void RendererStorageRD::material_set_shader(RID p_material, RID p_shader) {
}
void RendererStorageRD::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) {
- Material *material = material_owner.getornull(p_material);
+ Material *material = material_owner.get_or_null(p_material);
ERR_FAIL_COND(!material);
if (p_value.get_type() == Variant::NIL) {
material->params.erase(p_param);
} else {
+ ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT); //object not allowed
material->params[p_param] = p_value;
}
@@ -1613,7 +1712,7 @@ void RendererStorageRD::material_set_param(RID p_material, const StringName &p_p
}
Variant RendererStorageRD::material_get_param(RID p_material, const StringName &p_param) const {
- Material *material = material_owner.getornull(p_material);
+ Material *material = material_owner.get_or_null(p_material);
ERR_FAIL_COND_V(!material, Variant());
if (material->params.has(p_param)) {
return material->params[p_param];
@@ -1623,7 +1722,7 @@ Variant RendererStorageRD::material_get_param(RID p_material, const StringName &
}
void RendererStorageRD::material_set_next_pass(RID p_material, RID p_next_material) {
- Material *material = material_owner.getornull(p_material);
+ Material *material = material_owner.get_or_null(p_material);
ERR_FAIL_COND(!material);
if (material->next_pass == p_next_material) {
@@ -1639,7 +1738,7 @@ void RendererStorageRD::material_set_next_pass(RID p_material, RID p_next_materi
}
void RendererStorageRD::material_set_render_priority(RID p_material, int priority) {
- Material *material = material_owner.getornull(p_material);
+ Material *material = material_owner.get_or_null(p_material);
ERR_FAIL_COND(!material);
material->priority = priority;
if (material->data) {
@@ -1648,7 +1747,7 @@ void RendererStorageRD::material_set_render_priority(RID p_material, int priorit
}
bool RendererStorageRD::material_is_animated(RID p_material) {
- Material *material = material_owner.getornull(p_material);
+ Material *material = material_owner.get_or_null(p_material);
ERR_FAIL_COND_V(!material, false);
if (material->shader && material->shader->data) {
if (material->shader->data->is_animated()) {
@@ -1661,7 +1760,7 @@ bool RendererStorageRD::material_is_animated(RID p_material) {
}
bool RendererStorageRD::material_casts_shadows(RID p_material) {
- Material *material = material_owner.getornull(p_material);
+ Material *material = material_owner.get_or_null(p_material);
ERR_FAIL_COND_V(!material, true);
if (material->shader && material->shader->data) {
if (material->shader->data->casts_shadows()) {
@@ -1674,7 +1773,7 @@ bool RendererStorageRD::material_casts_shadows(RID p_material) {
}
void RendererStorageRD::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) {
- Material *material = material_owner.getornull(p_material);
+ Material *material = material_owner.get_or_null(p_material);
ERR_FAIL_COND(!material);
if (material->shader && material->shader->data) {
material->shader->data->get_instance_param_list(r_parameters);
@@ -1686,7 +1785,7 @@ void RendererStorageRD::material_get_instance_shader_parameters(RID p_material,
}
void RendererStorageRD::material_update_dependency(RID p_material, DependencyTracker *p_instance) {
- Material *material = material_owner.getornull(p_material);
+ Material *material = material_owner.get_or_null(p_material);
ERR_FAIL_COND(!material);
p_instance->update_dependency(&material->dependency);
if (material->next_pass.is_valid()) {
@@ -1699,73 +1798,183 @@ void RendererStorageRD::material_set_data_request_function(ShaderType p_shader_t
material_data_request_func[p_shader_type] = p_function;
}
-_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant &value, uint8_t *data, bool p_linear_color) {
+_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_array_size, const Variant &value, uint8_t *data, bool p_linear_color) {
switch (type) {
case ShaderLanguage::TYPE_BOOL: {
- bool v = value;
-
uint32_t *gui = (uint32_t *)data;
- *gui = v ? 1 : 0;
+
+ if (p_array_size > 0) {
+ const PackedInt32Array &ba = value;
+ int s = ba.size();
+ const int *r = ba.ptr();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = (r[i] != 0) ? 1 : 0;
+ } else {
+ gui[j] = 0;
+ }
+ gui[j + 1] = 0; // ignored
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ bool v = value;
+ gui[0] = v ? 1 : 0;
+ }
} break;
case ShaderLanguage::TYPE_BVEC2: {
- int v = value;
uint32_t *gui = (uint32_t *)data;
- gui[0] = v & 1 ? 1 : 0;
- gui[1] = v & 2 ? 1 : 0;
+ if (p_array_size > 0) {
+ const PackedInt32Array &ba = value;
+ int s = ba.size();
+ const int *r = ba.ptr();
+ int count = 2 * p_array_size;
+
+ for (int i = 0, j = 0; i < count; i += 2, j += 4) {
+ if (i < s) {
+ gui[j] = r[i] ? 1 : 0;
+ gui[j + 1] = r[i + 1] ? 1 : 0;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ }
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ int v = value;
+ gui[0] = v & 1 ? 1 : 0;
+ gui[1] = v & 2 ? 1 : 0;
+ }
} break;
case ShaderLanguage::TYPE_BVEC3: {
- int v = value;
uint32_t *gui = (uint32_t *)data;
- gui[0] = (v & 1) ? 1 : 0;
- gui[1] = (v & 2) ? 1 : 0;
- gui[2] = (v & 4) ? 1 : 0;
+ if (p_array_size > 0) {
+ const PackedInt32Array &ba = value;
+ int s = ba.size();
+ const int *r = ba.ptr();
+ int count = 3 * p_array_size;
+
+ for (int i = 0, j = 0; i < count; i += 3, j += 4) {
+ if (i < s) {
+ gui[j] = r[i] ? 1 : 0;
+ gui[j + 1] = r[i + 1] ? 1 : 0;
+ gui[j + 2] = r[i + 2] ? 1 : 0;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+ }
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ int v = value;
+ gui[0] = (v & 1) ? 1 : 0;
+ gui[1] = (v & 2) ? 1 : 0;
+ gui[2] = (v & 4) ? 1 : 0;
+ }
} break;
case ShaderLanguage::TYPE_BVEC4: {
- int v = value;
uint32_t *gui = (uint32_t *)data;
- gui[0] = (v & 1) ? 1 : 0;
- gui[1] = (v & 2) ? 1 : 0;
- gui[2] = (v & 4) ? 1 : 0;
- gui[3] = (v & 8) ? 1 : 0;
+ if (p_array_size > 0) {
+ const PackedInt32Array &ba = value;
+ int s = ba.size();
+ const int *r = ba.ptr();
+ int count = 4 * p_array_size;
+
+ for (int i = 0; i < count; i += 4) {
+ if (i < s) {
+ gui[i] = r[i] ? 1 : 0;
+ gui[i + 1] = r[i + 1] ? 1 : 0;
+ gui[i + 2] = r[i + 2] ? 1 : 0;
+ gui[i + 3] = r[i + 3] ? 1 : 0;
+ } else {
+ gui[i] = 0;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
+ }
+ }
+ } else {
+ int v = value;
+ gui[0] = (v & 1) ? 1 : 0;
+ gui[1] = (v & 2) ? 1 : 0;
+ gui[2] = (v & 4) ? 1 : 0;
+ gui[3] = (v & 8) ? 1 : 0;
+ }
} break;
case ShaderLanguage::TYPE_INT: {
- int v = value;
int32_t *gui = (int32_t *)data;
- gui[0] = v;
+ if (p_array_size > 0) {
+ Vector<int> iv = value;
+ int s = iv.size();
+ const int *r = iv.ptr();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = r[i];
+ } else {
+ gui[j] = 0;
+ }
+ gui[j + 1] = 0; // ignored
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ int v = value;
+ gui[0] = v;
+ }
} break;
case ShaderLanguage::TYPE_IVEC2: {
Vector<int> iv = value;
int s = iv.size();
int32_t *gui = (int32_t *)data;
- const int *r = iv.ptr();
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+ int count = 2 * p_array_size;
- for (int i = 0; i < 2; i++) {
+ const int *r = iv.ptr();
+ for (int i = 0, j = 0; i < count; i += 2, j += 4) {
if (i < s) {
- gui[i] = r[i];
+ gui[j] = r[i];
+ gui[j + 1] = r[i + 1];
} else {
- gui[i] = 0;
+ gui[j] = 0;
+ gui[j + 1] = 0;
}
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
}
-
} break;
case ShaderLanguage::TYPE_IVEC3: {
Vector<int> iv = value;
int s = iv.size();
int32_t *gui = (int32_t *)data;
- const int *r = iv.ptr();
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+ int count = 3 * p_array_size;
- for (int i = 0; i < 3; i++) {
+ const int *r = iv.ptr();
+ for (int i = 0, j = 0; i < count; i += 3, j += 4) {
if (i < s) {
- gui[i] = r[i];
+ gui[j] = r[i];
+ gui[j + 1] = r[i + 1];
+ gui[j + 2] = r[i + 2];
} else {
- gui[i] = 0;
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
}
+ gui[j + 3] = 0; // ignored
}
} break;
case ShaderLanguage::TYPE_IVEC4: {
@@ -1773,35 +1982,70 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
int s = iv.size();
int32_t *gui = (int32_t *)data;
- const int *r = iv.ptr();
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+ int count = 4 * p_array_size;
- for (int i = 0; i < 4; i++) {
+ const int *r = iv.ptr();
+ for (int i = 0; i < count; i += 4) {
if (i < s) {
gui[i] = r[i];
+ gui[i + 1] = r[i + 1];
+ gui[i + 2] = r[i + 2];
+ gui[i + 3] = r[i + 3];
} else {
gui[i] = 0;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
}
}
} break;
case ShaderLanguage::TYPE_UINT: {
- int v = value;
uint32_t *gui = (uint32_t *)data;
- gui[0] = v;
+ if (p_array_size > 0) {
+ Vector<int> iv = value;
+ int s = iv.size();
+ const int *r = iv.ptr();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = r[i];
+ } else {
+ gui[j] = 0;
+ }
+ gui[j + 1] = 0; // ignored
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ int v = value;
+ gui[0] = v;
+ }
} break;
case ShaderLanguage::TYPE_UVEC2: {
Vector<int> iv = value;
int s = iv.size();
uint32_t *gui = (uint32_t *)data;
- const int *r = iv.ptr();
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+ int count = 2 * p_array_size;
- for (int i = 0; i < 2; i++) {
+ const int *r = iv.ptr();
+ for (int i = 0, j = 0; i < count; i += 2, j += 4) {
if (i < s) {
- gui[i] = r[i];
+ gui[j] = r[i];
+ gui[j + 1] = r[i + 1];
} else {
- gui[i] = 0;
+ gui[j] = 0;
+ gui[j + 1] = 0;
}
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
}
} break;
case ShaderLanguage::TYPE_UVEC3: {
@@ -1809,141 +2053,370 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
int s = iv.size();
uint32_t *gui = (uint32_t *)data;
- const int *r = iv.ptr();
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+ int count = 3 * p_array_size;
- for (int i = 0; i < 3; i++) {
+ const int *r = iv.ptr();
+ for (int i = 0, j = 0; i < count; i += 3, j += 4) {
if (i < s) {
- gui[i] = r[i];
+ gui[j] = r[i];
+ gui[j + 1] = r[i + 1];
+ gui[j + 2] = r[i + 2];
} else {
- gui[i] = 0;
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
}
+ gui[j + 3] = 0; // ignored
}
-
} break;
case ShaderLanguage::TYPE_UVEC4: {
Vector<int> iv = value;
int s = iv.size();
uint32_t *gui = (uint32_t *)data;
- const int *r = iv.ptr();
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+ int count = 4 * p_array_size;
- for (int i = 0; i < 4; i++) {
+ const int *r = iv.ptr();
+ for (int i = 0; i < count; i++) {
if (i < s) {
gui[i] = r[i];
+ gui[i + 1] = r[i + 1];
+ gui[i + 2] = r[i + 2];
+ gui[i + 3] = r[i + 3];
} else {
gui[i] = 0;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
}
}
} break;
case ShaderLanguage::TYPE_FLOAT: {
- float v = value;
float *gui = (float *)data;
- gui[0] = v;
+ if (p_array_size > 0) {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = a[i];
+ } else {
+ gui[j] = 0;
+ }
+ gui[j + 1] = 0; // ignored
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ float v = value;
+ gui[0] = v;
+ }
} break;
case ShaderLanguage::TYPE_VEC2: {
- Vector2 v = value;
float *gui = (float *)data;
- gui[0] = v.x;
- gui[1] = v.y;
+ if (p_array_size > 0) {
+ const PackedVector2Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = a[i].x;
+ gui[j + 1] = a[i].y;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ }
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ Vector2 v = value;
+ gui[0] = v.x;
+ gui[1] = v.y;
+ }
} break;
case ShaderLanguage::TYPE_VEC3: {
- Vector3 v = value;
float *gui = (float *)data;
- gui[0] = v.x;
- gui[1] = v.y;
- gui[2] = v.z;
+ if (p_array_size > 0) {
+ const PackedVector3Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = a[i].x;
+ gui[j + 1] = a[i].y;
+ gui[j + 2] = a[i].z;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+ }
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ Vector3 v = value;
+ gui[0] = v.x;
+ gui[1] = v.y;
+ gui[2] = v.z;
+ }
} break;
case ShaderLanguage::TYPE_VEC4: {
float *gui = (float *)data;
- if (value.get_type() == Variant::COLOR) {
- Color v = value;
+ if (p_array_size > 0) {
+ if (value.get_type() == Variant::PACKED_COLOR_ARRAY) {
+ const PackedColorArray &a = value;
+ int s = a.size();
- if (p_linear_color) {
- v = v.to_linear();
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ Color color = a[i];
+ if (p_linear_color) {
+ color = color.to_linear();
+ }
+ gui[j] = color.r;
+ gui[j + 1] = color.g;
+ gui[j + 2] = color.b;
+ gui[j + 3] = color.a;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+ gui[j + 3] = 0;
+ }
+ }
+ } else {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+ int count = 4 * p_array_size;
+
+ for (int i = 0; i < count; i += 4) {
+ if (i + 3 < s) {
+ gui[i] = a[i];
+ gui[i + 1] = a[i + 1];
+ gui[i + 2] = a[i + 2];
+ gui[i + 3] = a[i + 3];
+ } else {
+ gui[i] = 0;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
+ }
+ }
}
+ } else {
+ if (value.get_type() == Variant::COLOR) {
+ Color v = value;
- gui[0] = v.r;
- gui[1] = v.g;
- gui[2] = v.b;
- gui[3] = v.a;
- } else if (value.get_type() == Variant::RECT2) {
- Rect2 v = value;
-
- gui[0] = v.position.x;
- gui[1] = v.position.y;
- gui[2] = v.size.x;
- gui[3] = v.size.y;
- } else if (value.get_type() == Variant::QUAT) {
- Quat v = value;
+ if (p_linear_color) {
+ v = v.to_linear();
+ }
- gui[0] = v.x;
- gui[1] = v.y;
- gui[2] = v.z;
- gui[3] = v.w;
- } else {
- Plane v = value;
+ gui[0] = v.r;
+ gui[1] = v.g;
+ gui[2] = v.b;
+ gui[3] = v.a;
+ } else if (value.get_type() == Variant::RECT2) {
+ Rect2 v = value;
+
+ gui[0] = v.position.x;
+ gui[1] = v.position.y;
+ gui[2] = v.size.x;
+ gui[3] = v.size.y;
+ } else if (value.get_type() == Variant::QUATERNION) {
+ Quaternion v = value;
+
+ gui[0] = v.x;
+ gui[1] = v.y;
+ gui[2] = v.z;
+ gui[3] = v.w;
+ } else {
+ Plane v = value;
- gui[0] = v.normal.x;
- gui[1] = v.normal.y;
- gui[2] = v.normal.z;
- gui[3] = v.d;
+ gui[0] = v.normal.x;
+ gui[1] = v.normal.y;
+ gui[2] = v.normal.z;
+ gui[3] = v.d;
+ }
}
} break;
case ShaderLanguage::TYPE_MAT2: {
- Transform2D v = value;
float *gui = (float *)data;
- //in std140 members of mat2 are treated as vec4s
- gui[0] = v.elements[0][0];
- gui[1] = v.elements[0][1];
- gui[2] = 0;
- gui[3] = 0;
- gui[4] = v.elements[1][0];
- gui[5] = v.elements[1][1];
- gui[6] = 0;
- gui[7] = 0;
+ if (p_array_size > 0) {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size * 4; i += 4, j += 8) {
+ if (i + 3 < s) {
+ gui[j] = a[i];
+ gui[j + 1] = a[i + 1];
+
+ gui[j + 4] = a[i + 2];
+ gui[j + 5] = a[i + 3];
+ } else {
+ gui[j] = 1;
+ gui[j + 1] = 0;
+
+ gui[j + 4] = 0;
+ gui[j + 5] = 1;
+ }
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ gui[j + 6] = 0; // ignored
+ gui[j + 7] = 0; // ignored
+ }
+ } else {
+ Transform2D v = value;
+
+ //in std140 members of mat2 are treated as vec4s
+ gui[0] = v.elements[0][0];
+ gui[1] = v.elements[0][1];
+ gui[2] = 0; // ignored
+ gui[3] = 0; // ignored
+
+ gui[4] = v.elements[1][0];
+ gui[5] = v.elements[1][1];
+ gui[6] = 0; // ignored
+ gui[7] = 0; // ignored
+ }
} break;
case ShaderLanguage::TYPE_MAT3: {
- Basis v = value;
float *gui = (float *)data;
- gui[0] = v.elements[0][0];
- gui[1] = v.elements[1][0];
- gui[2] = v.elements[2][0];
- gui[3] = 0;
- gui[4] = v.elements[0][1];
- gui[5] = v.elements[1][1];
- gui[6] = v.elements[2][1];
- gui[7] = 0;
- gui[8] = v.elements[0][2];
- gui[9] = v.elements[1][2];
- gui[10] = v.elements[2][2];
- gui[11] = 0;
+ if (p_array_size > 0) {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size * 9; i += 9, j += 12) {
+ if (i + 8 < s) {
+ gui[j] = a[i];
+ gui[j + 1] = a[i + 1];
+ gui[j + 2] = a[i + 2];
+
+ gui[j + 4] = a[i + 3];
+ gui[j + 5] = a[i + 4];
+ gui[j + 6] = a[i + 5];
+
+ gui[j + 8] = a[i + 6];
+ gui[j + 9] = a[i + 7];
+ gui[j + 10] = a[i + 8];
+ } else {
+ gui[j] = 1;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+
+ gui[j + 4] = 0;
+ gui[j + 5] = 1;
+ gui[j + 6] = 0;
+
+ gui[j + 8] = 0;
+ gui[j + 9] = 0;
+ gui[j + 10] = 1;
+ }
+ gui[j + 3] = 0; // ignored
+ gui[j + 7] = 0; // ignored
+ gui[j + 11] = 0; // ignored
+ }
+ } else {
+ Basis v = value;
+ gui[0] = v.elements[0][0];
+ gui[1] = v.elements[1][0];
+ gui[2] = v.elements[2][0];
+ gui[3] = 0; // ignored
+
+ gui[4] = v.elements[0][1];
+ gui[5] = v.elements[1][1];
+ gui[6] = v.elements[2][1];
+ gui[7] = 0; // ignored
+
+ gui[8] = v.elements[0][2];
+ gui[9] = v.elements[1][2];
+ gui[10] = v.elements[2][2];
+ gui[11] = 0; // ignored
+ }
} break;
case ShaderLanguage::TYPE_MAT4: {
- Transform v = value;
float *gui = (float *)data;
- gui[0] = v.basis.elements[0][0];
- gui[1] = v.basis.elements[1][0];
- gui[2] = v.basis.elements[2][0];
- gui[3] = 0;
- gui[4] = v.basis.elements[0][1];
- gui[5] = v.basis.elements[1][1];
- gui[6] = v.basis.elements[2][1];
- gui[7] = 0;
- gui[8] = v.basis.elements[0][2];
- gui[9] = v.basis.elements[1][2];
- gui[10] = v.basis.elements[2][2];
- gui[11] = 0;
- gui[12] = v.origin.x;
- gui[13] = v.origin.y;
- gui[14] = v.origin.z;
- gui[15] = 1;
+ if (p_array_size > 0) {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+
+ for (int i = 0; i < p_array_size * 16; i += 16) {
+ if (i + 15 < s) {
+ gui[i] = a[i];
+ gui[i + 1] = a[i + 1];
+ gui[i + 2] = a[i + 2];
+ gui[i + 3] = a[i + 3];
+
+ gui[i + 4] = a[i + 4];
+ gui[i + 5] = a[i + 5];
+ gui[i + 6] = a[i + 6];
+ gui[i + 7] = a[i + 7];
+
+ gui[i + 8] = a[i + 8];
+ gui[i + 9] = a[i + 9];
+ gui[i + 10] = a[i + 10];
+ gui[i + 11] = a[i + 11];
+
+ gui[i + 12] = a[i + 12];
+ gui[i + 13] = a[i + 13];
+ gui[i + 14] = a[i + 14];
+ gui[i + 15] = a[i + 15];
+ } else {
+ gui[i] = 1;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
+
+ gui[i + 4] = 0;
+ gui[i + 5] = 1;
+ gui[i + 6] = 0;
+ gui[i + 7] = 0;
+
+ gui[i + 8] = 0;
+ gui[i + 9] = 0;
+ gui[i + 10] = 1;
+ gui[i + 11] = 0;
+
+ gui[i + 12] = 0;
+ gui[i + 13] = 0;
+ gui[i + 14] = 0;
+ gui[i + 15] = 1;
+ }
+ }
+ } else {
+ Transform3D v = value;
+ gui[0] = v.basis.elements[0][0];
+ gui[1] = v.basis.elements[1][0];
+ gui[2] = v.basis.elements[2][0];
+ gui[3] = 0;
+
+ gui[4] = v.basis.elements[0][1];
+ gui[5] = v.basis.elements[1][1];
+ gui[6] = v.basis.elements[2][1];
+ gui[7] = 0;
+
+ gui[8] = v.basis.elements[0][2];
+ gui[9] = v.basis.elements[1][2];
+ gui[10] = v.basis.elements[2][2];
+ gui[11] = 0;
+
+ gui[12] = v.origin.x;
+ gui[13] = v.origin.y;
+ gui[14] = v.origin.z;
+ gui[15] = 1;
+ }
} break;
default: {
}
@@ -2102,19 +2575,23 @@ _FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type,
}
}
-_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, uint8_t *data) {
+_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, int p_array_size, uint8_t *data) {
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+
switch (type) {
case ShaderLanguage::TYPE_BOOL:
case ShaderLanguage::TYPE_INT:
case ShaderLanguage::TYPE_UINT:
case ShaderLanguage::TYPE_FLOAT: {
- memset(data, 0, 4);
+ memset(data, 0, 4 * p_array_size);
} break;
case ShaderLanguage::TYPE_BVEC2:
case ShaderLanguage::TYPE_IVEC2:
case ShaderLanguage::TYPE_UVEC2:
case ShaderLanguage::TYPE_VEC2: {
- memset(data, 0, 8);
+ memset(data, 0, 8 * p_array_size);
} break;
case ShaderLanguage::TYPE_BVEC3:
case ShaderLanguage::TYPE_IVEC3:
@@ -2124,16 +2601,16 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
case ShaderLanguage::TYPE_IVEC4:
case ShaderLanguage::TYPE_UVEC4:
case ShaderLanguage::TYPE_VEC4: {
- memset(data, 0, 16);
+ memset(data, 0, 16 * p_array_size);
} break;
case ShaderLanguage::TYPE_MAT2: {
- memset(data, 0, 32);
+ memset(data, 0, 32 * p_array_size);
} break;
case ShaderLanguage::TYPE_MAT3: {
- memset(data, 0, 48);
+ memset(data, 0, 48 * p_array_size);
} break;
case ShaderLanguage::TYPE_MAT4: {
- memset(data, 0, 64);
+ memset(data, 0, 64 * p_array_size);
} break;
default: {
@@ -2144,28 +2621,28 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
void RendererStorageRD::MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) {
bool uses_global_buffer = false;
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = p_uniforms.front(); E; E = E->next()) {
- if (E->get().order < 0) {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : p_uniforms) {
+ if (E.value.order < 0) {
continue; // texture, does not go here
}
- if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue; //instance uniforms don't appear in the bufferr
}
- if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) {
+ if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) {
//this is a global variable, get the index to it
RendererStorageRD *rs = base_singleton;
- GlobalVariables::Variable *gv = rs->global_variables.variables.getptr(E->key());
+ GlobalVariables::Variable *gv = rs->global_variables.variables.getptr(E.key);
uint32_t index = 0;
if (gv) {
index = gv->buffer_index;
} else {
- WARN_PRINT("Shader uses global uniform '" + E->key() + "', but it was removed at some point. Material will not display correctly.");
+ WARN_PRINT("Shader uses global uniform '" + E.key + "', but it was removed at some point. Material will not display correctly.");
}
- uint32_t offset = p_uniform_offsets[E->get().order];
+ uint32_t offset = p_uniform_offsets[E.value.order];
uint32_t *intptr = (uint32_t *)&p_buffer[offset];
*intptr = index;
uses_global_buffer = true;
@@ -2173,30 +2650,40 @@ void RendererStorageRD::MaterialData::update_uniform_buffer(const Map<StringName
}
//regular uniform
- uint32_t offset = p_uniform_offsets[E->get().order];
+ uint32_t offset = p_uniform_offsets[E.value.order];
#ifdef DEBUG_ENABLED
- uint32_t size = ShaderLanguage::get_type_size(E->get().type);
+ uint32_t size = 0U;
+ // The following code enforces a 16-byte alignment of uniform arrays.
+ if (E.value.array_size > 0) {
+ size = ShaderLanguage::get_type_size(E.value.type) * E.value.array_size;
+ int m = (16 * E.value.array_size);
+ if ((size % m) != 0U) {
+ size += m - (size % m);
+ }
+ } else {
+ size = ShaderLanguage::get_type_size(E.value.type);
+ }
ERR_CONTINUE(offset + size > p_buffer_size);
#endif
uint8_t *data = &p_buffer[offset];
- const Map<StringName, Variant>::Element *V = p_parameters.find(E->key());
+ const Map<StringName, Variant>::Element *V = p_parameters.find(E.key);
if (V) {
//user provided
- _fill_std140_variant_ubo_value(E->get().type, V->get(), data, p_use_linear_color);
+ _fill_std140_variant_ubo_value(E.value.type, E.value.array_size, V->get(), data, p_use_linear_color);
- } else if (E->get().default_value.size()) {
+ } else if (E.value.default_value.size()) {
//default value
- _fill_std140_ubo_value(E->get().type, E->get().default_value, data);
- //value=E->get().default_value;
+ _fill_std140_ubo_value(E.value.type, E.value.default_value, data);
+ //value=E.value.default_value;
} else {
//zero because it was not provided
- if (E->get().type == ShaderLanguage::TYPE_VEC4 && E->get().hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ if (E.value.type == ShaderLanguage::TYPE_VEC4 && E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
//colors must be set as black, with alpha as 1.0
- _fill_std140_variant_ubo_value(E->get().type, Color(0, 0, 0, 1), data, p_use_linear_color);
+ _fill_std140_variant_ubo_value(E.value.type, E.value.array_size, Color(0, 0, 0, 1), data, p_use_linear_color);
} else {
//else just zero it out
- _fill_std140_ubo_empty(E->get().type, data);
+ _fill_std140_ubo_empty(E.value.type, E.value.array_size, data);
}
}
}
@@ -2223,8 +2710,8 @@ RendererStorageRD::MaterialData::~MaterialData() {
//unregister global textures
RendererStorageRD *rs = base_singleton;
- for (Map<StringName, uint64_t>::Element *E = used_global_textures.front(); E; E = E->next()) {
- GlobalVariables::Variable *v = rs->global_variables.variables.getptr(E->key());
+ for (const KeyValue<StringName, uint64_t> &E : used_global_textures) {
+ GlobalVariables::Variable *v = rs->global_variables.variables.getptr(E.key);
if (v) {
v->texture_materials.erase(self);
}
@@ -2232,9 +2719,13 @@ RendererStorageRD::MaterialData::~MaterialData() {
//unregister material from those using global textures
rs->global_variables.materials_using_texture.erase(global_texture_E);
}
+
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ }
}
-void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) {
+void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, Map<int, RID>> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) {
RendererStorageRD *singleton = (RendererStorageRD *)RendererStorage::base_singleton;
#ifdef TOOLS_ENABLED
Texture *roughness_detect_texture = nullptr;
@@ -2245,10 +2736,11 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari
bool uses_global_textures = false;
global_textures_pass++;
- for (int i = 0; i < p_texture_uniforms.size(); i++) {
+ for (int i = 0, k = 0; i < p_texture_uniforms.size(); i++) {
const StringName &uniform_name = p_texture_uniforms[i].name;
+ int uniform_array_size = p_texture_uniforms[i].array_size;
- RID texture;
+ Vector<RID> textures;
if (p_texture_uniforms[i].global) {
RendererStorageRD *rs = base_singleton;
@@ -2269,86 +2761,154 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari
E->get() = global_textures_pass;
}
- texture = v->override.get_type() != Variant::NIL ? v->override : v->value;
+ textures.push_back(v->override.get_type() != Variant::NIL ? v->override : v->value);
}
} else {
WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it was removed at some point. Material will not display correctly.");
}
} else {
- if (!texture.is_valid()) {
- const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name);
- if (V) {
- texture = V->get();
+ const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name);
+ if (V) {
+ if (V->get().is_array()) {
+ Array array = (Array)V->get();
+ if (uniform_array_size > 0) {
+ for (int j = 0; j < array.size(); j++) {
+ textures.push_back(array[j]);
+ }
+ } else {
+ if (array.size() > 0) {
+ textures.push_back(array[0]);
+ }
+ }
+ } else {
+ textures.push_back(V->get());
}
}
- if (!texture.is_valid()) {
- const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name);
- if (W) {
- texture = W->get();
+ if (uniform_array_size > 0) {
+ if (textures.size() < uniform_array_size) {
+ const Map<StringName, Map<int, RID>>::Element *W = p_default_textures.find(uniform_name);
+ for (int j = textures.size(); j < uniform_array_size; j++) {
+ if (W && W->get().has(j)) {
+ textures.push_back(W->get()[j]);
+ } else {
+ textures.push_back(RID());
+ }
+ }
+ }
+ } else if (textures.is_empty()) {
+ const Map<StringName, Map<int, RID>>::Element *W = p_default_textures.find(uniform_name);
+ if (W && W->get().has(0)) {
+ textures.push_back(W->get()[0]);
}
}
}
RID rd_texture;
- if (texture.is_null()) {
+ if (textures.is_empty()) {
//check default usage
- switch (p_texture_uniforms[i].hint) {
- case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK:
- case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: {
- rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK);
+ switch (p_texture_uniforms[i].type) {
+ case ShaderLanguage::TYPE_ISAMPLER2D:
+ case ShaderLanguage::TYPE_USAMPLER2D:
+ case ShaderLanguage::TYPE_SAMPLER2D: {
+ switch (p_texture_uniforms[i].hint) {
+ case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK:
+ case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK);
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_NONE: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL);
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO);
+ } break;
+ default: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
+ } break;
+ }
} break;
- case ShaderLanguage::ShaderNode::Uniform::HINT_NONE: {
- rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL);
+
+ case ShaderLanguage::TYPE_SAMPLERCUBE: {
+ switch (p_texture_uniforms[i].hint) {
+ case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK:
+ case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
+ } break;
+ default: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_CUBEMAP_WHITE);
+ } break;
+ }
} break;
- case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: {
- rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO);
+ case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK);
} break;
- default: {
- rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
+
+ case ShaderLanguage::TYPE_ISAMPLER3D:
+ case ShaderLanguage::TYPE_USAMPLER3D:
+ case ShaderLanguage::TYPE_SAMPLER3D: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_3D_WHITE);
} break;
+
+ case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_USAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_SAMPLER2DARRAY: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
+ } break;
+
+ default: {
+ }
+ }
+#ifdef TOOLS_ENABLED
+ if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) {
+ roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel);
+ }
+#endif
+ if (uniform_array_size > 0) {
+ for (int j = 0; j < uniform_array_size; j++) {
+ p_textures[k++] = rd_texture;
+ }
+ } else {
+ p_textures[k++] = rd_texture;
}
} else {
bool srgb = p_use_linear_color && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO);
- Texture *tex = singleton->texture_owner.getornull(texture);
+ for (int j = 0; j < textures.size(); j++) {
+ Texture *tex = singleton->texture_owner.get_or_null(textures[j]);
- if (tex) {
- rd_texture = (srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture;
+ if (tex) {
+ rd_texture = (srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture;
#ifdef TOOLS_ENABLED
- if (tex->detect_3d_callback && p_use_linear_color) {
- tex->detect_3d_callback(tex->detect_3d_callback_ud);
- }
- if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) {
- if (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL) {
- normal_detect_texture = tex;
+ if (tex->detect_3d_callback && p_use_linear_color) {
+ tex->detect_3d_callback(tex->detect_3d_callback_ud);
}
- tex->detect_normal_callback(tex->detect_normal_callback_ud);
+ if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) {
+ if (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL) {
+ normal_detect_texture = tex;
+ }
+ tex->detect_normal_callback(tex->detect_normal_callback_ud);
+ }
+ if (tex->detect_roughness_callback && (p_texture_uniforms[i].hint >= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R || p_texture_uniforms[i].hint <= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_GRAY)) {
+ //find the normal texture
+ roughness_detect_texture = tex;
+ roughness_channel = RS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R);
+ }
+#endif
+ }
+ if (rd_texture.is_null()) {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
}
- if (tex->detect_roughness_callback && (p_texture_uniforms[i].hint >= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R || p_texture_uniforms[i].hint <= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_GRAY)) {
- //find the normal texture
- roughness_detect_texture = tex;
- roughness_channel = RS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R);
+#ifdef TOOLS_ENABLED
+ if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) {
+ roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel);
}
-
#endif
- }
-
- if (rd_texture.is_null()) {
- //wtf
- rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
+ p_textures[k++] = rd_texture;
}
}
-
- p_textures[i] = rd_texture;
- }
-#ifdef TOOLS_ENABLED
- if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) {
- roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel);
}
-#endif
{
//for textures no longer used, unregister them
List<Map<StringName, uint64_t>::Element *> to_delete;
@@ -2381,8 +2941,118 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari
}
}
+void RendererStorageRD::MaterialData::free_parameters_uniform_set(RID p_uniform_set) {
+ if (p_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(p_uniform_set)) {
+ RD::get_singleton()->uniform_set_set_invalidation_callback(p_uniform_set, nullptr, nullptr);
+ RD::get_singleton()->free(p_uniform_set);
+ }
+}
+
+bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, const Map<StringName, Map<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier) {
+ if ((uint32_t)ubo_data.size() != p_ubo_size) {
+ p_uniform_dirty = true;
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ uniform_buffer = RID();
+ }
+
+ ubo_data.resize(p_ubo_size);
+ if (ubo_data.size()) {
+ uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
+ memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
+ }
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->uniform_set_set_invalidation_callback(uniform_set, nullptr, nullptr);
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
+ }
+ }
+
+ //check whether buffer changed
+ if (p_uniform_dirty && ubo_data.size()) {
+ update_uniform_buffer(p_uniforms, p_uniform_offsets, p_parameters, ubo_data.ptrw(), ubo_data.size(), true);
+ RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), p_barrier);
+ }
+
+ uint32_t tex_uniform_count = 0U;
+ for (int i = 0; i < p_texture_uniforms.size(); i++) {
+ tex_uniform_count += uint32_t(p_texture_uniforms[i].array_size > 0 ? p_texture_uniforms[i].array_size : 1);
+ }
+
+ if ((uint32_t)texture_cache.size() != tex_uniform_count || p_textures_dirty) {
+ texture_cache.resize(tex_uniform_count);
+ p_textures_dirty = true;
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->uniform_set_set_invalidation_callback(uniform_set, nullptr, nullptr);
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
+ }
+ }
+
+ if (p_textures_dirty && tex_uniform_count) {
+ update_textures(p_parameters, p_default_texture_params, p_texture_uniforms, texture_cache.ptrw(), true);
+ }
+
+ if (p_ubo_size == 0 && p_texture_uniforms.size() == 0) {
+ // This material does not require an uniform set, so don't create it.
+ return false;
+ }
+
+ if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ //no reason to update uniform set, only UBO (or nothing) was needed to update
+ return false;
+ }
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ if (p_ubo_size) {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(uniform_buffer);
+ uniforms.push_back(u);
+ }
+
+ const RID *textures = texture_cache.ptrw();
+ for (int i = 0, k = 0; i < p_texture_uniforms.size(); i++) {
+ const int array_size = p_texture_uniforms[i].array_size;
+
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1 + k;
+ if (array_size > 0) {
+ for (int j = 0; j < array_size; j++) {
+ u.ids.push_back(textures[k++]);
+ }
+ } else {
+ u.ids.push_back(textures[k++]);
+ }
+ uniforms.push_back(u);
+ }
+ }
+
+ uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_shader_uniform_set);
+
+ RD::get_singleton()->uniform_set_set_invalidation_callback(uniform_set, _material_uniform_set_erased, &self);
+
+ return true;
+}
+
+void RendererStorageRD::_material_uniform_set_erased(const RID &p_set, void *p_material) {
+ RID rid = *(RID *)p_material;
+ Material *material = base_singleton->material_owner.get_or_null(rid);
+ if (material) {
+ material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL);
+ }
+}
+
void RendererStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) {
- Material *material = material_owner.getornull(p_material);
+ Material *material = material_owner.get_or_null(p_material);
if (material->shader_type != p_shader_type) {
return;
}
@@ -2392,20 +3062,23 @@ void RendererStorageRD::material_force_update_textures(RID p_material, ShaderTyp
}
void RendererStorageRD::_update_queued_materials() {
- Material *material = material_update_list;
- while (material) {
- Material *next = material->update_next;
+ while (material_update_list.first()) {
+ Material *material = material_update_list.first()->self();
+ bool uniforms_changed = false;
if (material->data) {
- material->data->update_parameters(material->params, material->uniform_dirty, material->texture_dirty);
+ uniforms_changed = material->data->update_parameters(material->params, material->uniform_dirty, material->texture_dirty);
}
- material->update_requested = false;
material->texture_dirty = false;
material->uniform_dirty = false;
- material->update_next = nullptr;
- material = next;
+
+ material_update_list.remove(&material->update_element);
+
+ if (uniforms_changed) {
+ //some implementations such as 3D renderer cache the matreial uniform set, so update is required
+ material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL);
+ }
}
- material_update_list = nullptr;
}
/* MESH API */
@@ -2420,7 +3093,7 @@ void RendererStorageRD::mesh_initialize(RID p_rid) {
void RendererStorageRD::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) {
ERR_FAIL_COND(p_blend_shape_count < 0);
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND(!mesh);
ERR_FAIL_COND(mesh->surface_count > 0); //surfaces already exist
@@ -2430,9 +3103,11 @@ void RendererStorageRD::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape
/// Returns stride
void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND(!mesh);
+ ERR_FAIL_COND(mesh->surface_count == RS::MAX_MESH_SURFACES);
+
#ifdef DEBUG_ENABLED
//do a validation, to catch errors first
{
@@ -2460,7 +3135,7 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su
} break;
case RS::ARRAY_COLOR: {
- attrib_stride += sizeof(int16_t) * 4;
+ attrib_stride += sizeof(uint32_t);
} break;
case RS::ARRAY_TEX_UV: {
attrib_stride += sizeof(float) * 2;
@@ -2548,6 +3223,7 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su
s->lods[i].index_buffer = RD::get_singleton()->index_buffer_create(indices, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.lods[i].index_data);
s->lods[i].index_array = RD::get_singleton()->index_array_create(s->lods[i].index_buffer, 0, indices);
s->lods[i].edge_length = p_surface.lods[i].edge_length;
+ s->lods[i].index_count = indices;
}
}
}
@@ -2615,9 +3291,7 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su
mesh->surfaces[mesh->surface_count] = s;
mesh->surface_count++;
- for (List<MeshInstance *>::Element *E = mesh->instances.front(); E; E = E->next()) {
- //update instances
- MeshInstance *mi = E->get();
+ for (MeshInstance *mi : mesh->instances) {
_mesh_instance_add_surface(mi, mesh, mesh->surface_count - 1);
}
@@ -2633,13 +3307,13 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su
}
int RendererStorageRD::mesh_get_blend_shape_count(RID p_mesh) const {
- const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ const Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND_V(!mesh, -1);
return mesh->blend_shape_count;
}
void RendererStorageRD::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND(!mesh);
ERR_FAIL_INDEX((int)p_mode, 2);
@@ -2647,13 +3321,13 @@ void RendererStorageRD::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode
}
RS::BlendShapeMode RendererStorageRD::mesh_get_blend_shape_mode(RID p_mesh) const {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND_V(!mesh, RS::BLEND_SHAPE_MODE_NORMALIZED);
return mesh->blend_shape_mode;
}
-void RendererStorageRD::mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+void RendererStorageRD::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND(!mesh);
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
ERR_FAIL_COND(p_data.size() == 0);
@@ -2663,8 +3337,32 @@ void RendererStorageRD::mesh_surface_update_region(RID p_mesh, int p_surface, in
RD::get_singleton()->buffer_update(mesh->surfaces[p_surface]->vertex_buffer, p_offset, data_size, r);
}
+void RendererStorageRD::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+ ERR_FAIL_COND(p_data.size() == 0);
+ ERR_FAIL_COND(mesh->surfaces[p_surface]->attribute_buffer.is_null());
+ uint64_t data_size = p_data.size();
+ const uint8_t *r = p_data.ptr();
+
+ RD::get_singleton()->buffer_update(mesh->surfaces[p_surface]->attribute_buffer, p_offset, data_size, r);
+}
+
+void RendererStorageRD::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+ ERR_FAIL_COND(p_data.size() == 0);
+ ERR_FAIL_COND(mesh->surfaces[p_surface]->skin_buffer.is_null());
+ uint64_t data_size = p_data.size();
+ const uint8_t *r = p_data.ptr();
+
+ RD::get_singleton()->buffer_update(mesh->surfaces[p_surface]->skin_buffer, p_offset, data_size, r);
+}
+
void RendererStorageRD::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND(!mesh);
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
mesh->surfaces[p_surface]->material = p_material;
@@ -2674,7 +3372,7 @@ void RendererStorageRD::mesh_surface_set_material(RID p_mesh, int p_surface, RID
}
RID RendererStorageRD::mesh_surface_get_material(RID p_mesh, int p_surface) const {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND_V(!mesh, RID());
ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RID());
@@ -2682,7 +3380,7 @@ RID RendererStorageRD::mesh_surface_get_material(RID p_mesh, int p_surface) cons
}
RS::SurfaceData RendererStorageRD::mesh_get_surface(RID p_mesh, int p_surface) const {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND_V(!mesh, RS::SurfaceData());
ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RS::SurfaceData());
@@ -2722,32 +3420,32 @@ RS::SurfaceData RendererStorageRD::mesh_get_surface(RID p_mesh, int p_surface) c
}
int RendererStorageRD::mesh_get_surface_count(RID p_mesh) const {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND_V(!mesh, 0);
return mesh->surface_count;
}
void RendererStorageRD::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND(!mesh);
mesh->custom_aabb = p_aabb;
}
AABB RendererStorageRD::mesh_get_custom_aabb(RID p_mesh) const {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND_V(!mesh, AABB());
return mesh->custom_aabb;
}
AABB RendererStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND_V(!mesh, AABB());
if (mesh->custom_aabb != AABB()) {
return mesh->custom_aabb;
}
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
if (!skeleton || skeleton->size == 0) {
return mesh->aabb;
@@ -2775,7 +3473,7 @@ AABB RendererStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
const float *dataptr = baseptr + j * 8;
- Transform mtx;
+ Transform3D mtx;
mtx.basis.elements[0].x = dataptr[0];
mtx.basis.elements[1].x = dataptr[1];
@@ -2802,7 +3500,7 @@ AABB RendererStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
const float *dataptr = baseptr + j * 12;
- Transform mtx;
+ Transform3D mtx;
mtx.basis.elements[0][0] = dataptr[0];
mtx.basis.elements[0][1] = dataptr[1];
@@ -2845,16 +3543,16 @@ AABB RendererStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
}
void RendererStorageRD::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND(!mesh);
- Mesh *shadow_mesh = mesh_owner.getornull(mesh->shadow_mesh);
+ Mesh *shadow_mesh = mesh_owner.get_or_null(mesh->shadow_mesh);
if (shadow_mesh) {
shadow_mesh->shadow_owners.erase(mesh);
}
mesh->shadow_mesh = p_shadow_mesh;
- shadow_mesh = mesh_owner.getornull(mesh->shadow_mesh);
+ shadow_mesh = mesh_owner.get_or_null(mesh->shadow_mesh);
if (shadow_mesh) {
shadow_mesh->shadow_owners.insert(mesh);
@@ -2864,7 +3562,7 @@ void RendererStorageRD::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
}
void RendererStorageRD::mesh_clear(RID p_mesh) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND(!mesh);
for (uint32_t i = 0; i < mesh->surface_count; i++) {
Mesh::Surface &s = *mesh->surfaces[i];
@@ -2904,8 +3602,7 @@ void RendererStorageRD::mesh_clear(RID p_mesh) {
mesh->surface_count = 0;
mesh->material_cache.clear();
//clear instance data
- for (List<MeshInstance *>::Element *E = mesh->instances.front(); E; E = E->next()) {
- MeshInstance *mi = E->get();
+ for (MeshInstance *mi : mesh->instances) {
_mesh_instance_clear(mi);
}
mesh->has_bone_weights = false;
@@ -2919,7 +3616,7 @@ void RendererStorageRD::mesh_clear(RID p_mesh) {
}
bool RendererStorageRD::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND_V(!mesh, false);
return mesh->blend_shape_count > 0 || (mesh->has_bone_weights && p_has_skeleton);
@@ -2928,10 +3625,11 @@ bool RendererStorageRD::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
/* MESH INSTANCE */
RID RendererStorageRD::mesh_instance_create(RID p_base) {
- Mesh *mesh = mesh_owner.getornull(p_base);
+ Mesh *mesh = mesh_owner.get_or_null(p_base);
ERR_FAIL_COND_V(!mesh, RID());
- MeshInstance *mi = memnew(MeshInstance);
+ RID rid = mesh_instance_owner.make_rid();
+ MeshInstance *mi = mesh_instance_owner.get_or_null(rid);
mi->mesh = mesh;
@@ -2943,10 +3641,10 @@ RID RendererStorageRD::mesh_instance_create(RID p_base) {
mi->dirty = true;
- return mesh_instance_owner.make_rid(mi);
+ return rid;
}
void RendererStorageRD::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) {
- MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance);
+ MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
if (mi->skeleton == p_skeleton) {
return;
}
@@ -2956,7 +3654,7 @@ void RendererStorageRD::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_sk
}
void RendererStorageRD::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) {
- MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance);
+ MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
ERR_FAIL_COND(!mi);
ERR_FAIL_INDEX(p_shape, (int)mi->blend_weights.size());
mi->blend_weights[p_shape] = p_weight;
@@ -3028,7 +3726,7 @@ void RendererStorageRD::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh,
}
void RendererStorageRD::mesh_instance_check_for_update(RID p_mesh_instance) {
- MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance);
+ MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
bool needs_update = mi->dirty;
@@ -3042,7 +3740,7 @@ void RendererStorageRD::mesh_instance_check_for_update(RID p_mesh_instance) {
}
if (!needs_update && mi->skeleton.is_valid()) {
- Skeleton *sk = skeleton_owner.getornull(mi->skeleton);
+ Skeleton *sk = skeleton_owner.get_or_null(mi->skeleton);
if (sk && sk->version != mi->skeleton_version) {
needs_update = true;
}
@@ -3073,7 +3771,7 @@ void RendererStorageRD::update_mesh_instances() {
while (dirty_mesh_instance_arrays.first()) {
MeshInstance *mi = dirty_mesh_instance_arrays.first()->self();
- Skeleton *sk = skeleton_owner.getornull(mi->skeleton);
+ Skeleton *sk = skeleton_owner.get_or_null(mi->skeleton);
for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
if (mi->surfaces[i].uniform_set == RID() || mi->mesh->surfaces[i]->uniform_set == RID()) {
@@ -3230,8 +3928,8 @@ void RendererStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surf
case RS::ARRAY_COLOR: {
vd.offset = attribute_stride;
- vd.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- attribute_stride += sizeof(int16_t) * 4;
+ vd.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ attribute_stride += sizeof(int8_t) * 4;
buffer = s->attribute_buffer;
} break;
case RS::ARRAY_TEX_UV: {
@@ -3320,7 +4018,7 @@ void RendererStorageRD::multimesh_initialize(RID p_rid) {
}
void RendererStorageRD::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND(!multimesh);
if (multimesh->instances == p_instances && multimesh->xform_format == p_transform_format && multimesh->uses_colors == p_use_colors && multimesh->uses_custom_data == p_use_custom_data) {
@@ -3330,6 +4028,7 @@ void RendererStorageRD::multimesh_allocate_data(RID p_multimesh, int p_instances
if (multimesh->buffer.is_valid()) {
RD::get_singleton()->free(multimesh->buffer);
multimesh->buffer = RID();
+ multimesh->uniform_set_2d = RID(); //cleared by dependency
multimesh->uniform_set_3d = RID(); //cleared by dependency
}
@@ -3362,13 +4061,13 @@ void RendererStorageRD::multimesh_allocate_data(RID p_multimesh, int p_instances
}
int RendererStorageRD::multimesh_get_instance_count(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND_V(!multimesh, 0);
return multimesh->instances;
}
void RendererStorageRD::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND(!multimesh);
if (multimesh->mesh == p_mesh) {
return;
@@ -3415,7 +4114,7 @@ void RendererStorageRD::_multimesh_make_local(MultiMesh *multimesh) const {
memcpy(w, r, buffer.size());
}
} else {
- memset(w, 0, multimesh->instances * multimesh->stride_cache * sizeof(float));
+ memset(w, 0, (size_t)multimesh->instances * multimesh->stride_cache * sizeof(float));
}
}
uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
@@ -3477,7 +4176,7 @@ void RendererStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const fl
AABB mesh_aabb = mesh_get_aabb(multimesh->mesh);
for (int i = 0; i < p_instances; i++) {
const float *data = p_data + multimesh->stride_cache * i;
- Transform t;
+ Transform3D t;
if (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_3D) {
t.basis.elements[0][0] = data[0];
@@ -3513,8 +4212,8 @@ void RendererStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const fl
multimesh->aabb = aabb;
}
-void RendererStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+void RendererStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND(!multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D);
@@ -3544,7 +4243,7 @@ void RendererStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_
}
void RendererStorageRD::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND(!multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D);
@@ -3570,7 +4269,7 @@ void RendererStorageRD::multimesh_instance_set_transform_2d(RID p_multimesh, int
}
void RendererStorageRD::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND(!multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
ERR_FAIL_COND(!multimesh->uses_colors);
@@ -3592,7 +4291,7 @@ void RendererStorageRD::multimesh_instance_set_color(RID p_multimesh, int p_inde
}
void RendererStorageRD::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND(!multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
ERR_FAIL_COND(!multimesh->uses_custom_data);
@@ -3614,21 +4313,21 @@ void RendererStorageRD::multimesh_instance_set_custom_data(RID p_multimesh, int
}
RID RendererStorageRD::multimesh_get_mesh(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND_V(!multimesh, RID());
return multimesh->mesh;
}
-Transform RendererStorageRD::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Transform());
- ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform());
- ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D, Transform());
+Transform3D RendererStorageRD::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Transform3D());
+ ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform3D());
+ ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D, Transform3D());
_multimesh_make_local(multimesh);
- Transform t;
+ Transform3D t;
{
const float *r = multimesh->data_cache.ptr();
@@ -3652,7 +4351,7 @@ Transform RendererStorageRD::multimesh_instance_get_transform(RID p_multimesh, i
}
Transform2D RendererStorageRD::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND_V(!multimesh, Transform2D());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform2D());
ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D, Transform2D());
@@ -3677,7 +4376,7 @@ Transform2D RendererStorageRD::multimesh_instance_get_transform_2d(RID p_multime
}
Color RendererStorageRD::multimesh_instance_get_color(RID p_multimesh, int p_index) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND_V(!multimesh, Color());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
ERR_FAIL_COND_V(!multimesh->uses_colors, Color());
@@ -3700,7 +4399,7 @@ Color RendererStorageRD::multimesh_instance_get_color(RID p_multimesh, int p_ind
}
Color RendererStorageRD::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND_V(!multimesh, Color());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
ERR_FAIL_COND_V(!multimesh->uses_custom_data, Color());
@@ -3723,7 +4422,7 @@ Color RendererStorageRD::multimesh_instance_get_custom_data(RID p_multimesh, int
}
void RendererStorageRD::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND(!multimesh);
ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache));
@@ -3756,7 +4455,7 @@ void RendererStorageRD::multimesh_set_buffer(RID p_multimesh, const Vector<float
}
Vector<float> RendererStorageRD::multimesh_get_buffer(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND_V(!multimesh, Vector<float>());
if (multimesh->buffer.is_null()) {
return Vector<float>();
@@ -3779,7 +4478,7 @@ Vector<float> RendererStorageRD::multimesh_get_buffer(RID p_multimesh) const {
}
void RendererStorageRD::multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND(!multimesh);
ERR_FAIL_COND(p_visible < -1 || p_visible > multimesh->instances);
if (multimesh->visible_instances == p_visible) {
@@ -3797,13 +4496,13 @@ void RendererStorageRD::multimesh_set_visible_instances(RID p_multimesh, int p_v
}
int RendererStorageRD::multimesh_get_visible_instances(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND_V(!multimesh, 0);
return multimesh->visible_instances;
}
AABB RendererStorageRD::multimesh_get_aabb(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND_V(!multimesh, AABB());
if (multimesh->aabb_dirty) {
const_cast<RendererStorageRD *>(this)->_update_dirty_multimeshes();
@@ -3822,20 +4521,21 @@ void RendererStorageRD::_update_dirty_multimeshes() {
if (multimesh->data_cache_used_dirty_regions) {
uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
- uint32_t visible_region_count = (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+ uint32_t visible_region_count = visible_instances == 0 ? 0 : (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
uint32_t region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float);
if (multimesh->data_cache_used_dirty_regions > 32 || multimesh->data_cache_used_dirty_regions > visible_region_count / 2) {
//if there too many dirty regions, or represent the majority of regions, just copy all, else transfer cost piles up too much
- RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * multimesh->stride_cache * sizeof(float)), data);
+ RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * (uint32_t)multimesh->stride_cache * (uint32_t)sizeof(float)), data);
} else {
//not that many regions? update them all
for (uint32_t i = 0; i < visible_region_count; i++) {
if (multimesh->data_cache_dirty_regions[i]) {
- uint64_t offset = i * region_size;
- uint64_t size = multimesh->stride_cache * multimesh->instances * sizeof(float);
- RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[i * region_size]);
+ uint32_t offset = i * region_size;
+ uint32_t size = multimesh->stride_cache * (uint32_t)multimesh->instances * (uint32_t)sizeof(float);
+ uint32_t region_start_index = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * i;
+ RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[region_start_index]);
}
}
}
@@ -3874,7 +4574,7 @@ void RendererStorageRD::particles_initialize(RID p_rid) {
}
void RendererStorageRD::particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
if (particles->mode == p_mode) {
return;
@@ -3886,14 +4586,15 @@ void RendererStorageRD::particles_set_mode(RID p_particles, RS::ParticlesMode p_
}
void RendererStorageRD::particles_set_emitting(RID p_particles, bool p_emitting) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->emitting = p_emitting;
}
bool RendererStorageRD::particles_get_emitting(RID p_particles) {
- Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer.");
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, false);
return particles->emitting;
@@ -3948,7 +4649,7 @@ void RendererStorageRD::_particles_free_data(Particles *particles) {
}
void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
if (particles->amount == p_amount) {
@@ -3967,56 +4668,57 @@ void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) {
particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES);
}
-void RendererStorageRD::particles_set_lifetime(RID p_particles, float p_lifetime) {
- Particles *particles = particles_owner.getornull(p_particles);
+void RendererStorageRD::particles_set_lifetime(RID p_particles, double p_lifetime) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->lifetime = p_lifetime;
}
void RendererStorageRD::particles_set_one_shot(RID p_particles, bool p_one_shot) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->one_shot = p_one_shot;
}
-void RendererStorageRD::particles_set_pre_process_time(RID p_particles, float p_time) {
- Particles *particles = particles_owner.getornull(p_particles);
+void RendererStorageRD::particles_set_pre_process_time(RID p_particles, double p_time) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->pre_process_time = p_time;
}
-void RendererStorageRD::particles_set_explosiveness_ratio(RID p_particles, float p_ratio) {
- Particles *particles = particles_owner.getornull(p_particles);
+void RendererStorageRD::particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->explosiveness = p_ratio;
}
-void RendererStorageRD::particles_set_randomness_ratio(RID p_particles, float p_ratio) {
- Particles *particles = particles_owner.getornull(p_particles);
+void RendererStorageRD::particles_set_randomness_ratio(RID p_particles, real_t p_ratio) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->randomness = p_ratio;
}
void RendererStorageRD::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->custom_aabb = p_aabb;
particles->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
}
-void RendererStorageRD::particles_set_speed_scale(RID p_particles, float p_scale) {
- Particles *particles = particles_owner.getornull(p_particles);
+void RendererStorageRD::particles_set_speed_scale(RID p_particles, double p_scale) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->speed_scale = p_scale;
}
void RendererStorageRD::particles_set_use_local_coordinates(RID p_particles, bool p_enable) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->use_local_coords = p_enable;
+ particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES);
}
void RendererStorageRD::particles_set_fixed_fps(RID p_particles, int p_fps) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->fixed_fps = p_fps;
@@ -4032,21 +4734,21 @@ void RendererStorageRD::particles_set_fixed_fps(RID p_particles, int p_fps) {
}
void RendererStorageRD::particles_set_interpolate(RID p_particles, bool p_enable) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->interpolate = p_enable;
}
void RendererStorageRD::particles_set_fractional_delta(RID p_particles, bool p_enable) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->fractional_delta = p_enable;
}
-void RendererStorageRD::particles_set_trails(RID p_particles, bool p_enable, float p_length) {
- Particles *particles = particles_owner.getornull(p_particles);
+void RendererStorageRD::particles_set_trails(RID p_particles, bool p_enable, double p_length) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
ERR_FAIL_COND(p_length < 0.1);
p_length = MIN(10.0, p_length);
@@ -4064,8 +4766,8 @@ void RendererStorageRD::particles_set_trails(RID p_particles, bool p_enable, flo
particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES);
}
-void RendererStorageRD::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses) {
- Particles *particles = particles_owner.getornull(p_particles);
+void RendererStorageRD::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
if (particles->trail_bind_pose_buffer.is_valid() && particles->trail_bind_poses.size() != p_bind_poses.size()) {
_particles_free_data(particles);
@@ -4081,50 +4783,50 @@ void RendererStorageRD::particles_set_trail_bind_poses(RID p_particles, const Ve
particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES);
}
-void RendererStorageRD::particles_set_collision_base_size(RID p_particles, float p_size) {
- Particles *particles = particles_owner.getornull(p_particles);
+void RendererStorageRD::particles_set_collision_base_size(RID p_particles, real_t p_size) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->collision_base_size = p_size;
}
void RendererStorageRD::particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->transform_align = p_transform_align;
}
void RendererStorageRD::particles_set_process_material(RID p_particles, RID p_material) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->process_material = p_material;
}
void RendererStorageRD::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->draw_order = p_order;
}
void RendererStorageRD::particles_set_draw_passes(RID p_particles, int p_passes) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->draw_passes.resize(p_passes);
}
void RendererStorageRD::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
ERR_FAIL_INDEX(p_pass, particles->draw_passes.size());
particles->draw_passes.write[p_pass] = p_mesh;
}
void RendererStorageRD::particles_restart(RID p_particles) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->restart_request = true;
@@ -4148,7 +4850,7 @@ void RendererStorageRD::_particles_allocate_emission_buffer(Particles *particles
}
void RendererStorageRD::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
ERR_FAIL_COND(p_particles == p_subemitter_particles);
@@ -4160,8 +4862,8 @@ void RendererStorageRD::particles_set_subemitter(RID p_particles, RID p_subemitt
}
}
-void RendererStorageRD::particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
- Particles *particles = particles_owner.getornull(p_particles);
+void RendererStorageRD::particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
ERR_FAIL_COND(particles->amount == 0);
@@ -4204,7 +4906,7 @@ void RendererStorageRD::particles_emit(RID p_particles, const Transform &p_trans
}
void RendererStorageRD::particles_request_process(RID p_particles) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
if (!particles->dirty) {
@@ -4215,7 +4917,11 @@ void RendererStorageRD::particles_request_process(RID p_particles) {
}
AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) {
- const Particles *particles = particles_owner.getornull(p_particles);
+ if (RSG::threaded) {
+ WARN_PRINT_ONCE("Calling this function with threaded rendering enabled stalls the renderer, use with care.");
+ }
+
+ const Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, AABB());
int total_amount = particles->amount;
@@ -4223,18 +4929,16 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) {
total_amount *= particles->trail_bind_poses.size();
}
- Vector<ParticleData> data;
- data.resize(total_amount);
-
Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(particles->particle_buffer);
+ ERR_FAIL_COND_V(buffer.size() != (int)(total_amount * sizeof(ParticleData)), AABB());
- Transform inv = particles->emission_transform.affine_inverse();
+ Transform3D inv = particles->emission_transform.affine_inverse();
AABB aabb;
if (buffer.size()) {
bool first = true;
- const ParticleData *particle_data = (const ParticleData *)data.ptr();
+ const ParticleData *particle_data = reinterpret_cast<const ParticleData *>(buffer.ptr());
for (int i = 0; i < total_amount; i++) {
if (particle_data[i].active) {
Vector3 pos = Vector3(particle_data[i].xform[12], particle_data[i].xform[13], particle_data[i].xform[14]);
@@ -4265,28 +4969,28 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) {
}
AABB RendererStorageRD::particles_get_aabb(RID p_particles) const {
- const Particles *particles = particles_owner.getornull(p_particles);
+ const Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, AABB());
return particles->custom_aabb;
}
-void RendererStorageRD::particles_set_emission_transform(RID p_particles, const Transform &p_transform) {
- Particles *particles = particles_owner.getornull(p_particles);
+void RendererStorageRD::particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->emission_transform = p_transform;
}
int RendererStorageRD::particles_get_draw_passes(RID p_particles) const {
- const Particles *particles = particles_owner.getornull(p_particles);
+ const Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, 0);
return particles->draw_passes.size();
}
RID RendererStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const {
- const Particles *particles = particles_owner.getornull(p_particles);
+ const Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, RID());
ERR_FAIL_INDEX_V(p_pass, particles->draw_passes.size(), RID());
@@ -4294,18 +4998,27 @@ RID RendererStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pass)
}
void RendererStorageRD::particles_add_collision(RID p_particles, RID p_particles_collision_instance) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->collisions.insert(p_particles_collision_instance);
}
void RendererStorageRD::particles_remove_collision(RID p_particles, RID p_particles_collision_instance) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
particles->collisions.erase(p_particles_collision_instance);
}
-void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta) {
+void RendererStorageRD::particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->has_sdf_collision = p_enable;
+ particles->sdf_collision_transform = p_xform;
+ particles->sdf_collision_to_screen = p_to_screen;
+ particles->sdf_collision_texture = p_texture;
+}
+
+void RendererStorageRD::_particles_process(Particles *p_particles, double p_delta) {
if (p_particles->particles_material_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_particles->particles_material_uniform_set)) {
Vector<RD::Uniform> uniforms;
@@ -4339,7 +5052,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 3;
- Particles *sub_emitter = particles_owner.getornull(p_particles->sub_emitter);
+ Particles *sub_emitter = particles_owner.get_or_null(p_particles->sub_emitter);
if (sub_emitter) {
if (sub_emitter->emission_buffer == nullptr) { //no emission buffer, allocate emission buffer
_particles_allocate_emission_buffer(sub_emitter);
@@ -4354,7 +5067,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
p_particles->particles_material_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 1);
}
- float new_phase = Math::fmod((float)p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, (float)1.0);
+ double new_phase = Math::fmod((double)p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, 1.0);
//move back history (if there is any)
for (uint32_t i = p_particles->frame_history.size() - 1; i > 0; i--) {
@@ -4386,7 +5099,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
frame_params.randomness = p_particles->randomness;
if (p_particles->use_local_coords) {
- store_transform(Transform(), frame_params.emission_transform);
+ store_transform(Transform3D(), frame_params.emission_transform);
} else {
store_transform(p_particles->emission_transform, frame_params.emission_transform);
}
@@ -4406,20 +5119,64 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
RID collision_3d_textures[ParticlesFrameParams::MAX_3D_TEXTURES];
RID collision_heightmap_texture;
- Transform to_particles;
+ Transform3D to_particles;
if (p_particles->use_local_coords) {
to_particles = p_particles->emission_transform.affine_inverse();
}
+
+ if (p_particles->has_sdf_collision && RD::get_singleton()->texture_is_valid(p_particles->sdf_collision_texture)) {
+ //2D collision
+
+ Transform2D xform = p_particles->sdf_collision_transform; //will use dotproduct manually so invert beforehand
+ Transform2D revert = xform.affine_inverse();
+ frame_params.collider_count = 1;
+ frame_params.colliders[0].transform[0] = xform.elements[0][0];
+ frame_params.colliders[0].transform[1] = xform.elements[0][1];
+ frame_params.colliders[0].transform[2] = 0;
+ frame_params.colliders[0].transform[3] = xform.elements[2][0];
+
+ frame_params.colliders[0].transform[4] = xform.elements[1][0];
+ frame_params.colliders[0].transform[5] = xform.elements[1][1];
+ frame_params.colliders[0].transform[6] = 0;
+ frame_params.colliders[0].transform[7] = xform.elements[2][1];
+
+ frame_params.colliders[0].transform[8] = revert.elements[0][0];
+ frame_params.colliders[0].transform[9] = revert.elements[0][1];
+ frame_params.colliders[0].transform[10] = 0;
+ frame_params.colliders[0].transform[11] = revert.elements[2][0];
+
+ frame_params.colliders[0].transform[12] = revert.elements[1][0];
+ frame_params.colliders[0].transform[13] = revert.elements[1][1];
+ frame_params.colliders[0].transform[14] = 0;
+ frame_params.colliders[0].transform[15] = revert.elements[2][1];
+
+ frame_params.colliders[0].extents[0] = p_particles->sdf_collision_to_screen.size.x;
+ frame_params.colliders[0].extents[1] = p_particles->sdf_collision_to_screen.size.y;
+ frame_params.colliders[0].extents[2] = p_particles->sdf_collision_to_screen.position.x;
+ frame_params.colliders[0].scale = p_particles->sdf_collision_to_screen.position.y;
+ frame_params.colliders[0].texture_index = 0;
+ frame_params.colliders[0].type = ParticlesFrameParams::COLLISION_TYPE_2D_SDF;
+
+ collision_heightmap_texture = p_particles->sdf_collision_texture;
+
+ //replace in all other history frames where used because parameters are no longer valid if screen moves
+ for (uint32_t i = 1; i < p_particles->frame_history.size(); i++) {
+ if (p_particles->frame_history[i].collider_count > 0 && p_particles->frame_history[i].colliders[0].type == ParticlesFrameParams::COLLISION_TYPE_2D_SDF) {
+ p_particles->frame_history[i].colliders[0] = frame_params.colliders[0];
+ }
+ }
+ }
+
uint32_t collision_3d_textures_used = 0;
for (const Set<RID>::Element *E = p_particles->collisions.front(); E; E = E->next()) {
- ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(E->get());
+ ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(E->get());
if (!pci || !pci->active) {
continue;
}
- ParticlesCollision *pc = particles_collision_owner.getornull(pci->collision);
+ ParticlesCollision *pc = particles_collision_owner.get_or_null(pci->collision);
ERR_CONTINUE(!pc);
- Transform to_collider = pci->transform;
+ Transform3D to_collider = pci->transform;
if (p_particles->use_local_coords) {
to_collider = to_particles * to_collider;
}
@@ -4564,7 +5321,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
for (uint32_t i = 0; i < ParticlesFrameParams::MAX_3D_TEXTURES; i++) {
RID rd_tex;
if (i < collision_3d_textures_used) {
- Texture *t = texture_owner.getornull(collision_3d_textures[i]);
+ Texture *t = texture_owner.get_or_null(collision_3d_textures[i]);
if (t && t->type == Texture::TYPE_3D) {
rd_tex = t->rd_texture;
}
@@ -4609,7 +5366,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
p_particles->force_sub_emit = false; //reset
- Particles *sub_emitter = particles_owner.getornull(p_particles->sub_emitter);
+ Particles *sub_emitter = particles_owner.get_or_null(p_particles->sub_emitter);
if (sub_emitter && sub_emitter->emission_storage_buffer.is_valid()) {
// print_line("updating subemitter buffer");
@@ -4657,6 +5414,8 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
ERR_FAIL_COND(!m);
+ p_particles->has_collision_cache = m->shader_data->uses_collision;
+
//todo should maybe compute all particle systems together?
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, m->shader_data->pipeline);
@@ -4664,7 +5423,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->particles_material_uniform_set, 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->collision_textures_uniform_set, 2);
- if (m->uniform_set.is_valid()) {
+ if (m->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(m->uniform_set)) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, m->uniform_set, 3);
}
@@ -4687,7 +5446,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
}
void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
@@ -4740,6 +5499,11 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &
copy_push_constant.trail_total = 1;
copy_push_constant.frame_delta = 0.0;
}
+
+ copy_push_constant.order_by_lifetime = (particles->draw_order == RS::PARTICLES_DRAW_ORDER_LIFETIME || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME);
+ copy_push_constant.lifetime_split = MIN(particles->amount * particles->phase, particles->amount - 1);
+ copy_push_constant.lifetime_reverse = particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME;
+
copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0;
copy_push_constant.total_particles = particles->amount;
@@ -4771,7 +5535,7 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &
RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1);
RD::get_singleton()->compute_list_end();
- effects.sort_buffer(particles->particles_sort_uniform_set, particles->amount);
+ effects->sort_buffer(particles->particles_sort_uniform_set, particles->amount);
}
copy_push_constant.total_particles *= copy_push_constant.total_particles;
@@ -4943,14 +5707,14 @@ void RendererStorageRD::update_particles() {
bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0;
if (particles->clear && particles->pre_process_time > 0.0) {
- float frame_time;
+ double frame_time;
if (fixed_fps > 0) {
frame_time = 1.0 / fixed_fps;
} else {
frame_time = 1.0 / 30.0;
}
- float todo = particles->pre_process_time;
+ double todo = particles->pre_process_time;
while (todo >= 0) {
_particles_process(particles, frame_time);
@@ -4959,8 +5723,8 @@ void RendererStorageRD::update_particles() {
}
if (fixed_fps > 0) {
- float frame_time;
- float decr;
+ double frame_time;
+ double decr;
if (zero_time_scale) {
frame_time = 0.0;
decr = 1.0 / fixed_fps;
@@ -4968,13 +5732,13 @@ void RendererStorageRD::update_particles() {
frame_time = 1.0 / fixed_fps;
decr = frame_time;
}
- float delta = RendererCompositorRD::singleton->get_frame_delta_time();
+ double delta = RendererCompositorRD::singleton->get_frame_delta_time();
if (delta > 0.1) { //avoid recursive stalls if fps goes below 10
delta = 0.1;
} else if (delta <= 0.0) { //unlikely but..
delta = 0.001;
}
- float todo = particles->frame_remainder + delta;
+ double todo = particles->frame_remainder + delta;
while (todo >= frame_time) {
_particles_process(particles, frame_time);
@@ -5019,6 +5783,10 @@ void RendererStorageRD::update_particles() {
copy_push_constant.frame_delta = 0.0;
}
+ copy_push_constant.order_by_lifetime = (particles->draw_order == RS::PARTICLES_DRAW_ORDER_LIFETIME || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME);
+ copy_push_constant.lifetime_split = MIN(particles->amount * particles->phase, particles->amount - 1);
+ copy_push_constant.lifetime_reverse = particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME;
+
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[particles->mode == RS::PARTICLES_MODE_2D ? ParticlesShader::COPY_MODE_FILL_INSTANCES_2D : ParticlesShader::COPY_MODE_FILL_INSTANCES]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
@@ -5035,7 +5803,8 @@ void RendererStorageRD::update_particles() {
}
bool RendererStorageRD::particles_is_inactive(RID p_particles) const {
- const Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer.");
+ const Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, false);
return !particles->emitting && particles->inactive;
}
@@ -5049,6 +5818,7 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) {
valid = false;
ubo_size = 0;
uniforms.clear();
+ uses_collision = false;
if (code == String()) {
return; //just invalid, but no error
@@ -5068,11 +5838,12 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) {
actions.usage_flag_pointers["TIME"] = &uses_time;
*/
+ actions.usage_flag_pointers["COLLIDED"] = &uses_collision;
+
actions.uniforms = &uniforms;
Error err = base_singleton->particles_shader.compiler.compile(RS::SHADER_PARTICLES, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = base_singleton->particles_shader.shader.version_create();
@@ -5092,47 +5863,56 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) {
valid = true;
}
-void RendererStorageRD::ParticlesShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+void RendererStorageRD::ParticlesShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
- default_texture_params.erase(p_name);
+ if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
+ default_texture_params[p_name].erase(p_index);
+
+ if (default_texture_params[p_name].is_empty()) {
+ default_texture_params.erase(p_name);
+ }
+ }
} else {
- default_texture_params[p_name] = p_texture;
+ if (!default_texture_params.has(p_name)) {
+ default_texture_params[p_name] = Map<int, RID>();
+ }
+ default_texture_params[p_name][p_index] = p_texture;
}
}
void RendererStorageRD::ParticlesShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
Map<int, StringName> order;
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
- if (E->get().texture_order >= 0) {
- order[E->get().texture_order + 100000] = E->key();
+ if (E.value.texture_order >= 0) {
+ order[E.value.texture_order + 100000] = E.key;
} else {
- order[E->get().order] = E->key();
+ order[E.value.order] = E.key;
}
}
- for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
- pi.name = E->get();
+ for (const KeyValue<int, StringName> &E : order) {
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
+ pi.name = E.value;
p_param_list->push_back(pi);
}
}
void RendererStorageRD::ParticlesShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
RendererStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E->get());
- p.info.name = E->key(); //supply name
- p.index = E->get().instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+ p.info = ShaderLanguage::uniform_to_property_info(E.value);
+ p.info.name = E.key; //supply name
+ p.index = E.value.instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
p_param_list->push_back(p);
}
}
@@ -5157,7 +5937,7 @@ Variant RendererStorageRD::ParticlesShaderData::get_default_parameter(const Stri
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
return Variant();
}
@@ -5182,94 +5962,14 @@ RendererStorageRD::ShaderData *RendererStorageRD::_create_particles_shader_func(
return shader_data;
}
-void RendererStorageRD::ParticlesMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+bool RendererStorageRD::ParticlesMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
uniform_set_updated = true;
- if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
- p_uniform_dirty = true;
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- uniform_buffer = RID();
- }
-
- ubo_data.resize(shader_data->ubo_size);
- if (ubo_data.size()) {
- uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
- memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
- }
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
-
- //check whether buffer changed
- if (p_uniform_dirty && ubo_data.size()) {
- update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
- RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw());
- }
-
- uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
-
- if ((uint32_t)texture_cache.size() != tex_uniform_count) {
- texture_cache.resize(tex_uniform_count);
- p_textures_dirty = true;
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
-
- if (p_textures_dirty && tex_uniform_count) {
- update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true);
- }
-
- if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) {
- // This material does not require an uniform set, so don't create it.
- return;
- }
-
- if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- //no reason to update uniform set, only UBO (or nothing) was needed to update
- return;
- }
-
- Vector<RD::Uniform> uniforms;
-
- {
- if (shader_data->ubo_size) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 0;
- u.ids.push_back(uniform_buffer);
- uniforms.push_back(u);
- }
-
- const RID *textures = texture_cache.ptrw();
- for (uint32_t i = 0; i < tex_uniform_count; i++) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1 + i;
- u.ids.push_back(textures[i]);
- uniforms.push_back(u);
- }
- }
-
- uniform_set = RD::get_singleton()->uniform_set_create(uniforms, base_singleton->particles_shader.shader.version_get_shader(shader_data->version, 0), 3);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, base_singleton->particles_shader.shader.version_get_shader(shader_data->version, 0), 3);
}
RendererStorageRD::ParticlesMaterialData::~ParticlesMaterialData() {
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- }
-
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- }
+ free_parameters_uniform_set(uniform_set);
}
RendererStorageRD::MaterialData *RendererStorageRD::_create_particles_material_func(ParticlesShaderData *p_shader) {
@@ -5291,7 +5991,7 @@ void RendererStorageRD::particles_collision_initialize(RID p_rid) {
}
RID RendererStorageRD::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const {
- ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND_V(!particles_collision, RID());
ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, RID());
@@ -5326,7 +6026,7 @@ RID RendererStorageRD::particles_collision_get_heightfield_framebuffer(RID p_par
}
void RendererStorageRD::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) {
- ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND(!particles_collision);
if (p_type == particles_collision->type) {
@@ -5342,13 +6042,13 @@ void RendererStorageRD::particles_collision_set_collision_type(RID p_particles_c
}
void RendererStorageRD::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) {
- ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND(!particles_collision);
particles_collision->cull_mask = p_cull_mask;
}
-void RendererStorageRD::particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) {
- ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
+void RendererStorageRD::particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND(!particles_collision);
particles_collision->radius = p_radius;
@@ -5356,49 +6056,49 @@ void RendererStorageRD::particles_collision_set_sphere_radius(RID p_particles_co
}
void RendererStorageRD::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) {
- ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND(!particles_collision);
particles_collision->extents = p_extents;
particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
}
-void RendererStorageRD::particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength) {
- ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
+void RendererStorageRD::particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND(!particles_collision);
particles_collision->attractor_strength = p_strength;
}
-void RendererStorageRD::particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality) {
- ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
+void RendererStorageRD::particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND(!particles_collision);
particles_collision->attractor_directionality = p_directionality;
}
-void RendererStorageRD::particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve) {
- ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
+void RendererStorageRD::particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND(!particles_collision);
particles_collision->attractor_attenuation = p_curve;
}
void RendererStorageRD::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) {
- ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND(!particles_collision);
particles_collision->field_texture = p_texture;
}
void RendererStorageRD::particles_collision_height_field_update(RID p_particles_collision) {
- ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND(!particles_collision);
particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
}
void RendererStorageRD::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) {
- ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND(!particles_collision);
ERR_FAIL_INDEX(p_resolution, RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX);
@@ -5415,7 +6115,7 @@ void RendererStorageRD::particles_collision_set_height_field_resolution(RID p_pa
}
AABB RendererStorageRD::particles_collision_get_aabb(RID p_particles_collision) const {
- ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND_V(!particles_collision, AABB());
switch (particles_collision->type) {
@@ -5438,13 +6138,13 @@ AABB RendererStorageRD::particles_collision_get_aabb(RID p_particles_collision)
}
Vector3 RendererStorageRD::particles_collision_get_extents(RID p_particles_collision) const {
- const ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
+ const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND_V(!particles_collision, Vector3());
return particles_collision->extents;
}
bool RendererStorageRD::particles_collision_is_heightfield(RID p_particles_collision) const {
- const ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
+ const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND_V(!particles_collision, false);
return particles_collision->type == RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE;
}
@@ -5454,17 +6154,146 @@ RID RendererStorageRD::particles_collision_instance_create(RID p_collision) {
pci.collision = p_collision;
return particles_collision_instance_owner.make_rid(pci);
}
-void RendererStorageRD::particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) {
- ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(p_collision_instance);
+void RendererStorageRD::particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) {
+ ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(p_collision_instance);
ERR_FAIL_COND(!pci);
pci->transform = p_transform;
}
void RendererStorageRD::particles_collision_instance_set_active(RID p_collision_instance, bool p_active) {
- ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(p_collision_instance);
+ ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(p_collision_instance);
ERR_FAIL_COND(!pci);
pci->active = p_active;
}
+/* FOG VOLUMES */
+
+RID RendererStorageRD::fog_volume_allocate() {
+ return fog_volume_owner.allocate_rid();
+}
+void RendererStorageRD::fog_volume_initialize(RID p_rid) {
+ fog_volume_owner.initialize_rid(p_rid, FogVolume());
+}
+
+void RendererStorageRD::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) {
+ FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
+ ERR_FAIL_COND(!fog_volume);
+
+ if (p_shape == fog_volume->shape) {
+ return;
+ }
+
+ fog_volume->shape = p_shape;
+ fog_volume->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
+}
+
+void RendererStorageRD::fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) {
+ FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
+ ERR_FAIL_COND(!fog_volume);
+
+ fog_volume->extents = p_extents;
+ fog_volume->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
+}
+
+void RendererStorageRD::fog_volume_set_material(RID p_fog_volume, RID p_material) {
+ FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
+ ERR_FAIL_COND(!fog_volume);
+ fog_volume->material = p_material;
+}
+
+RID RendererStorageRD::fog_volume_get_material(RID p_fog_volume) const {
+ FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
+ ERR_FAIL_COND_V(!fog_volume, RID());
+
+ return fog_volume->material;
+}
+
+RS::FogVolumeShape RendererStorageRD::fog_volume_get_shape(RID p_fog_volume) const {
+ FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
+ ERR_FAIL_COND_V(!fog_volume, RS::FOG_VOLUME_SHAPE_BOX);
+
+ return fog_volume->shape;
+}
+
+AABB RendererStorageRD::fog_volume_get_aabb(RID p_fog_volume) const {
+ FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
+ ERR_FAIL_COND_V(!fog_volume, AABB());
+
+ switch (fog_volume->shape) {
+ case RS::FOG_VOLUME_SHAPE_ELLIPSOID:
+ case RS::FOG_VOLUME_SHAPE_BOX: {
+ AABB aabb;
+ aabb.position = -fog_volume->extents;
+ aabb.size = fog_volume->extents * 2;
+ return aabb;
+ }
+ default: {
+ // Need some size otherwise will get culled
+ return AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
+ }
+ }
+
+ return AABB();
+}
+
+Vector3 RendererStorageRD::fog_volume_get_extents(RID p_fog_volume) const {
+ const FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
+ ERR_FAIL_COND_V(!fog_volume, Vector3());
+ return fog_volume->extents;
+}
+
+/* VISIBILITY NOTIFIER */
+
+RID RendererStorageRD::visibility_notifier_allocate() {
+ return visibility_notifier_owner.allocate_rid();
+}
+void RendererStorageRD::visibility_notifier_initialize(RID p_notifier) {
+ visibility_notifier_owner.initialize_rid(p_notifier, VisibilityNotifier());
+}
+void RendererStorageRD::visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) {
+ VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier);
+ ERR_FAIL_COND(!vn);
+ vn->aabb = p_aabb;
+ vn->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
+}
+void RendererStorageRD::visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) {
+ VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier);
+ ERR_FAIL_COND(!vn);
+ vn->enter_callback = p_enter_callbable;
+ vn->exit_callback = p_exit_callable;
+}
+
+AABB RendererStorageRD::visibility_notifier_get_aabb(RID p_notifier) const {
+ const VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier);
+ ERR_FAIL_COND_V(!vn, AABB());
+ return vn->aabb;
+}
+void RendererStorageRD::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) {
+ VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier);
+ ERR_FAIL_COND(!vn);
+
+ if (p_enter) {
+ if (!vn->enter_callback.is_null()) {
+ if (p_deferred) {
+ vn->enter_callback.call_deferred(nullptr, 0);
+ } else {
+ Variant r;
+ Callable::CallError ce;
+ vn->enter_callback.call(nullptr, 0, r, ce);
+ }
+ }
+ } else {
+ if (!vn->exit_callback.is_null()) {
+ if (p_deferred) {
+ vn->exit_callback.call_deferred(nullptr, 0);
+ } else {
+ Variant r;
+ Callable::CallError ce;
+ vn->exit_callback.call(nullptr, 0, r, ce);
+ }
+ }
+ }
+}
+
/* SKELETON API */
RID RendererStorageRD::skeleton_allocate() {
@@ -5483,7 +6312,7 @@ void RendererStorageRD::_skeleton_make_dirty(Skeleton *skeleton) {
}
void RendererStorageRD::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton) {
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
ERR_FAIL_COND(!skeleton);
ERR_FAIL_COND(p_bones < 0);
@@ -5526,14 +6355,14 @@ void RendererStorageRD::skeleton_allocate_data(RID p_skeleton, int p_bones, bool
}
int RendererStorageRD::skeleton_get_bone_count(RID p_skeleton) const {
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
ERR_FAIL_COND_V(!skeleton, 0);
return skeleton->size;
}
-void RendererStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) {
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+void RendererStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) {
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
ERR_FAIL_COND(!skeleton);
ERR_FAIL_INDEX(p_bone, skeleton->size);
@@ -5557,16 +6386,16 @@ void RendererStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone,
_skeleton_make_dirty(skeleton);
}
-Transform RendererStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const {
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+Transform3D RendererStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const {
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND_V(!skeleton, Transform());
- ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform());
- ERR_FAIL_COND_V(skeleton->use_2d, Transform());
+ ERR_FAIL_COND_V(!skeleton, Transform3D());
+ ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform3D());
+ ERR_FAIL_COND_V(skeleton->use_2d, Transform3D());
const float *dataptr = skeleton->data.ptr() + p_bone * 12;
- Transform t;
+ Transform3D t;
t.basis.elements[0][0] = dataptr[0];
t.basis.elements[0][1] = dataptr[1];
@@ -5585,7 +6414,7 @@ Transform RendererStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p_b
}
void RendererStorageRD::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
ERR_FAIL_COND(!skeleton);
ERR_FAIL_INDEX(p_bone, skeleton->size);
@@ -5606,7 +6435,7 @@ void RendererStorageRD::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bon
}
Transform2D RendererStorageRD::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const {
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
ERR_FAIL_COND_V(!skeleton, Transform2D());
ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform2D());
@@ -5626,7 +6455,7 @@ Transform2D RendererStorageRD::skeleton_bone_get_transform_2d(RID p_skeleton, in
}
void RendererStorageRD::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) {
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
ERR_FAIL_COND(!skeleton->use_2d);
@@ -5705,17 +6534,21 @@ void RendererStorageRD::spot_light_initialize(RID p_light) {
}
void RendererStorageRD::light_set_color(RID p_light, const Color &p_color) {
- Light *light = light_owner.getornull(p_light);
+ Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
light->color = p_color;
}
void RendererStorageRD::light_set_param(RID p_light, RS::LightParam p_param, float p_value) {
- Light *light = light_owner.getornull(p_light);
+ Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
ERR_FAIL_INDEX(p_param, RS::LIGHT_PARAM_MAX);
+ if (light->param[p_param] == p_value) {
+ return;
+ }
+
switch (p_param) {
case RS::LIGHT_PARAM_RANGE:
case RS::LIGHT_PARAM_SPOT_ANGLE:
@@ -5729,6 +6562,12 @@ void RendererStorageRD::light_set_param(RID p_light, RS::LightParam p_param, flo
light->version++;
light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT);
} break;
+ case RS::LIGHT_PARAM_SIZE: {
+ if ((light->param[p_param] > CMP_EPSILON) != (p_value > CMP_EPSILON)) {
+ //changing from no size to size and the opposite
+ light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR);
+ }
+ } break;
default: {
}
}
@@ -5737,7 +6576,7 @@ void RendererStorageRD::light_set_param(RID p_light, RS::LightParam p_param, flo
}
void RendererStorageRD::light_set_shadow(RID p_light, bool p_enabled) {
- Light *light = light_owner.getornull(p_light);
+ Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
light->shadow = p_enabled;
@@ -5746,13 +6585,13 @@ void RendererStorageRD::light_set_shadow(RID p_light, bool p_enabled) {
}
void RendererStorageRD::light_set_shadow_color(RID p_light, const Color &p_color) {
- Light *light = light_owner.getornull(p_light);
+ Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
light->shadow_color = p_color;
}
void RendererStorageRD::light_set_projector(RID p_light, RID p_texture) {
- Light *light = light_owner.getornull(p_light);
+ Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
if (light->projector == p_texture) {
@@ -5765,20 +6604,23 @@ void RendererStorageRD::light_set_projector(RID p_light, RID p_texture) {
light->projector = p_texture;
- if (light->type != RS::LIGHT_DIRECTIONAL && light->projector.is_valid()) {
- texture_add_to_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI);
+ if (light->type != RS::LIGHT_DIRECTIONAL) {
+ if (light->projector.is_valid()) {
+ texture_add_to_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI);
+ }
+ light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR);
}
}
void RendererStorageRD::light_set_negative(RID p_light, bool p_enable) {
- Light *light = light_owner.getornull(p_light);
+ Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
light->negative = p_enable;
}
void RendererStorageRD::light_set_cull_mask(RID p_light, uint32_t p_mask) {
- Light *light = light_owner.getornull(p_light);
+ Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
light->cull_mask = p_mask;
@@ -5788,7 +6630,7 @@ void RendererStorageRD::light_set_cull_mask(RID p_light, uint32_t p_mask) {
}
void RendererStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {
- Light *light = light_owner.getornull(p_light);
+ Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
light->reverse_cull = p_enabled;
@@ -5798,7 +6640,7 @@ void RendererStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_ena
}
void RendererStorageRD::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) {
- Light *light = light_owner.getornull(p_light);
+ Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
light->bake_mode = p_bake_mode;
@@ -5808,7 +6650,7 @@ void RendererStorageRD::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bak
}
void RendererStorageRD::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) {
- Light *light = light_owner.getornull(p_light);
+ Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
light->max_sdfgi_cascade = p_cascade;
@@ -5818,7 +6660,7 @@ void RendererStorageRD::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_casc
}
void RendererStorageRD::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) {
- Light *light = light_owner.getornull(p_light);
+ Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
light->omni_shadow_mode = p_mode;
@@ -5828,14 +6670,14 @@ void RendererStorageRD::light_omni_set_shadow_mode(RID p_light, RS::LightOmniSha
}
RS::LightOmniShadowMode RendererStorageRD::light_omni_get_shadow_mode(RID p_light) {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, RS::LIGHT_OMNI_SHADOW_CUBE);
return light->omni_shadow_mode;
}
void RendererStorageRD::light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) {
- Light *light = light_owner.getornull(p_light);
+ Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
light->directional_shadow_mode = p_mode;
@@ -5844,7 +6686,7 @@ void RendererStorageRD::light_directional_set_shadow_mode(RID p_light, RS::Light
}
void RendererStorageRD::light_directional_set_blend_splits(RID p_light, bool p_enable) {
- Light *light = light_owner.getornull(p_light);
+ Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
light->directional_blend_splits = p_enable;
@@ -5853,70 +6695,56 @@ void RendererStorageRD::light_directional_set_blend_splits(RID p_light, bool p_e
}
bool RendererStorageRD::light_directional_get_blend_splits(RID p_light) const {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, false);
return light->directional_blend_splits;
}
void RendererStorageRD::light_directional_set_sky_only(RID p_light, bool p_sky_only) {
- Light *light = light_owner.getornull(p_light);
+ Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
light->directional_sky_only = p_sky_only;
}
bool RendererStorageRD::light_directional_is_sky_only(RID p_light) const {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, false);
return light->directional_sky_only;
}
RS::LightDirectionalShadowMode RendererStorageRD::light_directional_get_shadow_mode(RID p_light) {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
return light->directional_shadow_mode;
}
-void RendererStorageRD::light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) {
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND(!light);
-
- light->directional_range_mode = p_range_mode;
-}
-
-RS::LightDirectionalShadowDepthRangeMode RendererStorageRD::light_directional_get_shadow_depth_range_mode(RID p_light) const {
- const Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE);
-
- return light->directional_range_mode;
-}
-
uint32_t RendererStorageRD::light_get_max_sdfgi_cascade(RID p_light) {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, 0);
return light->max_sdfgi_cascade;
}
RS::LightBakeMode RendererStorageRD::light_get_bake_mode(RID p_light) {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, RS::LIGHT_BAKE_DISABLED);
return light->bake_mode;
}
uint64_t RendererStorageRD::light_get_version(RID p_light) const {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, 0);
return light->version;
}
AABB RendererStorageRD::light_get_aabb(RID p_light) const {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, AABB());
switch (light->type) {
@@ -5947,7 +6775,7 @@ void RendererStorageRD::reflection_probe_initialize(RID p_reflection_probe) {
}
void RendererStorageRD::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND(!reflection_probe);
reflection_probe->update_mode = p_mode;
@@ -5955,35 +6783,35 @@ void RendererStorageRD::reflection_probe_set_update_mode(RID p_probe, RS::Reflec
}
void RendererStorageRD::reflection_probe_set_intensity(RID p_probe, float p_intensity) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND(!reflection_probe);
reflection_probe->intensity = p_intensity;
}
void RendererStorageRD::reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND(!reflection_probe);
reflection_probe->ambient_mode = p_mode;
}
void RendererStorageRD::reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND(!reflection_probe);
reflection_probe->ambient_color = p_color;
}
void RendererStorageRD::reflection_probe_set_ambient_energy(RID p_probe, float p_energy) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND(!reflection_probe);
reflection_probe->ambient_color_energy = p_energy;
}
void RendererStorageRD::reflection_probe_set_max_distance(RID p_probe, float p_distance) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND(!reflection_probe);
reflection_probe->max_distance = p_distance;
@@ -5992,7 +6820,7 @@ void RendererStorageRD::reflection_probe_set_max_distance(RID p_probe, float p_d
}
void RendererStorageRD::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND(!reflection_probe);
if (reflection_probe->extents == p_extents) {
@@ -6003,7 +6831,7 @@ void RendererStorageRD::reflection_probe_set_extents(RID p_probe, const Vector3
}
void RendererStorageRD::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND(!reflection_probe);
reflection_probe->origin_offset = p_offset;
@@ -6011,7 +6839,7 @@ void RendererStorageRD::reflection_probe_set_origin_offset(RID p_probe, const Ve
}
void RendererStorageRD::reflection_probe_set_as_interior(RID p_probe, bool p_enable) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND(!reflection_probe);
reflection_probe->interior = p_enable;
@@ -6019,14 +6847,14 @@ void RendererStorageRD::reflection_probe_set_as_interior(RID p_probe, bool p_ena
}
void RendererStorageRD::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND(!reflection_probe);
reflection_probe->box_projection = p_enable;
}
void RendererStorageRD::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND(!reflection_probe);
reflection_probe->enable_shadows = p_enable;
@@ -6034,7 +6862,7 @@ void RendererStorageRD::reflection_probe_set_enable_shadows(RID p_probe, bool p_
}
void RendererStorageRD::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND(!reflection_probe);
reflection_probe->cull_mask = p_layers;
@@ -6042,7 +6870,7 @@ void RendererStorageRD::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_l
}
void RendererStorageRD::reflection_probe_set_resolution(RID p_probe, int p_resolution) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND(!reflection_probe);
ERR_FAIL_COND(p_resolution < 32);
@@ -6050,7 +6878,7 @@ void RendererStorageRD::reflection_probe_set_resolution(RID p_probe, int p_resol
}
void RendererStorageRD::reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND(!reflection_probe);
reflection_probe->lod_threshold = p_ratio;
@@ -6059,7 +6887,7 @@ void RendererStorageRD::reflection_probe_set_lod_threshold(RID p_probe, float p_
}
AABB RendererStorageRD::reflection_probe_get_aabb(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, AABB());
AABB aabb;
@@ -6070,96 +6898,96 @@ AABB RendererStorageRD::reflection_probe_get_aabb(RID p_probe) const {
}
RS::ReflectionProbeUpdateMode RendererStorageRD::reflection_probe_get_update_mode(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, RS::REFLECTION_PROBE_UPDATE_ALWAYS);
return reflection_probe->update_mode;
}
uint32_t RendererStorageRD::reflection_probe_get_cull_mask(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, 0);
return reflection_probe->cull_mask;
}
Vector3 RendererStorageRD::reflection_probe_get_extents(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, Vector3());
return reflection_probe->extents;
}
Vector3 RendererStorageRD::reflection_probe_get_origin_offset(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, Vector3());
return reflection_probe->origin_offset;
}
bool RendererStorageRD::reflection_probe_renders_shadows(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, false);
return reflection_probe->enable_shadows;
}
float RendererStorageRD::reflection_probe_get_origin_max_distance(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, 0);
return reflection_probe->max_distance;
}
float RendererStorageRD::reflection_probe_get_lod_threshold(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, 0);
return reflection_probe->lod_threshold;
}
int RendererStorageRD::reflection_probe_get_resolution(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, 0);
return reflection_probe->resolution;
}
float RendererStorageRD::reflection_probe_get_intensity(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, 0);
return reflection_probe->intensity;
}
bool RendererStorageRD::reflection_probe_is_interior(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, false);
return reflection_probe->interior;
}
bool RendererStorageRD::reflection_probe_is_box_projection(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, false);
return reflection_probe->box_projection;
}
RS::ReflectionProbeAmbientMode RendererStorageRD::reflection_probe_get_ambient_mode(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, RS::REFLECTION_PROBE_AMBIENT_DISABLED);
return reflection_probe->ambient_mode;
}
Color RendererStorageRD::reflection_probe_get_ambient_color(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, Color());
return reflection_probe->ambient_color;
}
float RendererStorageRD::reflection_probe_get_ambient_color_energy(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, 0);
return reflection_probe->ambient_color_energy;
@@ -6173,14 +7001,14 @@ void RendererStorageRD::decal_initialize(RID p_decal) {
}
void RendererStorageRD::decal_set_extents(RID p_decal, const Vector3 &p_extents) {
- Decal *decal = decal_owner.getornull(p_decal);
+ Decal *decal = decal_owner.get_or_null(p_decal);
ERR_FAIL_COND(!decal);
decal->extents = p_extents;
decal->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
}
void RendererStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) {
- Decal *decal = decal_owner.getornull(p_decal);
+ Decal *decal = decal_owner.get_or_null(p_decal);
ERR_FAIL_COND(!decal);
ERR_FAIL_INDEX(p_type, RS::DECAL_TEXTURE_MAX);
@@ -6204,32 +7032,32 @@ void RendererStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type,
}
void RendererStorageRD::decal_set_emission_energy(RID p_decal, float p_energy) {
- Decal *decal = decal_owner.getornull(p_decal);
+ Decal *decal = decal_owner.get_or_null(p_decal);
ERR_FAIL_COND(!decal);
decal->emission_energy = p_energy;
}
void RendererStorageRD::decal_set_albedo_mix(RID p_decal, float p_mix) {
- Decal *decal = decal_owner.getornull(p_decal);
+ Decal *decal = decal_owner.get_or_null(p_decal);
ERR_FAIL_COND(!decal);
decal->albedo_mix = p_mix;
}
void RendererStorageRD::decal_set_modulate(RID p_decal, const Color &p_modulate) {
- Decal *decal = decal_owner.getornull(p_decal);
+ Decal *decal = decal_owner.get_or_null(p_decal);
ERR_FAIL_COND(!decal);
decal->modulate = p_modulate;
}
void RendererStorageRD::decal_set_cull_mask(RID p_decal, uint32_t p_layers) {
- Decal *decal = decal_owner.getornull(p_decal);
+ Decal *decal = decal_owner.get_or_null(p_decal);
ERR_FAIL_COND(!decal);
decal->cull_mask = p_layers;
decal->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
}
void RendererStorageRD::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) {
- Decal *decal = decal_owner.getornull(p_decal);
+ Decal *decal = decal_owner.get_or_null(p_decal);
ERR_FAIL_COND(!decal);
decal->distance_fade = p_enabled;
decal->distance_fade_begin = p_begin;
@@ -6237,55 +7065,55 @@ void RendererStorageRD::decal_set_distance_fade(RID p_decal, bool p_enabled, flo
}
void RendererStorageRD::decal_set_fade(RID p_decal, float p_above, float p_below) {
- Decal *decal = decal_owner.getornull(p_decal);
+ Decal *decal = decal_owner.get_or_null(p_decal);
ERR_FAIL_COND(!decal);
decal->upper_fade = p_above;
decal->lower_fade = p_below;
}
void RendererStorageRD::decal_set_normal_fade(RID p_decal, float p_fade) {
- Decal *decal = decal_owner.getornull(p_decal);
+ Decal *decal = decal_owner.get_or_null(p_decal);
ERR_FAIL_COND(!decal);
decal->normal_fade = p_fade;
}
AABB RendererStorageRD::decal_get_aabb(RID p_decal) const {
- Decal *decal = decal_owner.getornull(p_decal);
+ Decal *decal = decal_owner.get_or_null(p_decal);
ERR_FAIL_COND_V(!decal, AABB());
return AABB(-decal->extents, decal->extents * 2.0);
}
-RID RendererStorageRD::gi_probe_allocate() {
- return gi_probe_owner.allocate_rid();
+RID RendererStorageRD::voxel_gi_allocate() {
+ return voxel_gi_owner.allocate_rid();
}
-void RendererStorageRD::gi_probe_initialize(RID p_gi_probe) {
- gi_probe_owner.initialize_rid(p_gi_probe, GIProbe());
+void RendererStorageRD::voxel_gi_initialize(RID p_voxel_gi) {
+ voxel_gi_owner.initialize_rid(p_voxel_gi, VoxelGI());
}
-void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererStorageRD::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- if (gi_probe->octree_buffer.is_valid()) {
- RD::get_singleton()->free(gi_probe->octree_buffer);
- RD::get_singleton()->free(gi_probe->data_buffer);
- if (gi_probe->sdf_texture.is_valid()) {
- RD::get_singleton()->free(gi_probe->sdf_texture);
+ if (voxel_gi->octree_buffer.is_valid()) {
+ RD::get_singleton()->free(voxel_gi->octree_buffer);
+ RD::get_singleton()->free(voxel_gi->data_buffer);
+ if (voxel_gi->sdf_texture.is_valid()) {
+ RD::get_singleton()->free(voxel_gi->sdf_texture);
}
- gi_probe->sdf_texture = RID();
- gi_probe->octree_buffer = RID();
- gi_probe->data_buffer = RID();
- gi_probe->octree_buffer_size = 0;
- gi_probe->data_buffer_size = 0;
- gi_probe->cell_count = 0;
+ voxel_gi->sdf_texture = RID();
+ voxel_gi->octree_buffer = RID();
+ voxel_gi->data_buffer = RID();
+ voxel_gi->octree_buffer_size = 0;
+ voxel_gi->data_buffer_size = 0;
+ voxel_gi->cell_count = 0;
}
- gi_probe->to_cell_xform = p_to_cell_xform;
- gi_probe->bounds = p_aabb;
- gi_probe->octree_size = p_octree_size;
- gi_probe->level_counts = p_level_counts;
+ voxel_gi->to_cell_xform = p_to_cell_xform;
+ voxel_gi->bounds = p_aabb;
+ voxel_gi->octree_size = p_octree_size;
+ voxel_gi->level_counts = p_level_counts;
if (p_octree_cells.size()) {
ERR_FAIL_COND(p_octree_cells.size() % 32 != 0); //cells size must be a multiple of 32
@@ -6294,42 +7122,42 @@ void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform &
ERR_FAIL_COND(p_data_cells.size() != (int)cell_count * 16); //see that data size matches
- gi_probe->cell_count = cell_count;
- gi_probe->octree_buffer = RD::get_singleton()->storage_buffer_create(p_octree_cells.size(), p_octree_cells);
- gi_probe->octree_buffer_size = p_octree_cells.size();
- gi_probe->data_buffer = RD::get_singleton()->storage_buffer_create(p_data_cells.size(), p_data_cells);
- gi_probe->data_buffer_size = p_data_cells.size();
+ voxel_gi->cell_count = cell_count;
+ voxel_gi->octree_buffer = RD::get_singleton()->storage_buffer_create(p_octree_cells.size(), p_octree_cells);
+ voxel_gi->octree_buffer_size = p_octree_cells.size();
+ voxel_gi->data_buffer = RD::get_singleton()->storage_buffer_create(p_data_cells.size(), p_data_cells);
+ voxel_gi->data_buffer_size = p_data_cells.size();
if (p_distance_field.size()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8_UNORM;
- tf.width = gi_probe->octree_size.x;
- tf.height = gi_probe->octree_size.y;
- tf.depth = gi_probe->octree_size.z;
+ tf.width = voxel_gi->octree_size.x;
+ tf.height = voxel_gi->octree_size.y;
+ tf.depth = voxel_gi->octree_size.z;
tf.texture_type = RD::TEXTURE_TYPE_3D;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
Vector<Vector<uint8_t>> s;
s.push_back(p_distance_field);
- gi_probe->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView(), s);
+ voxel_gi->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView(), s);
}
#if 0
{
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8_UNORM;
- tf.width = gi_probe->octree_size.x;
- tf.height = gi_probe->octree_size.y;
- tf.depth = gi_probe->octree_size.z;
+ tf.width = voxel_gi->octree_size.x;
+ tf.height = voxel_gi->octree_size.y;
+ tf.depth = voxel_gi->octree_size.z;
tf.type = RD::TEXTURE_TYPE_3D;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UNORM);
tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UINT);
- gi_probe->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ voxel_gi->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
}
RID shared_tex;
{
RD::TextureView tv;
tv.format_override = RD::DATA_FORMAT_R8_UINT;
- shared_tex = RD::get_singleton()->texture_create_shared(tv, gi_probe->sdf_texture);
+ shared_tex = RD::get_singleton()->texture_create_shared(tv, voxel_gi->sdf_texture);
}
//update SDF texture
Vector<RD::Uniform> uniforms;
@@ -6337,14 +7165,14 @@ void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform &
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 1;
- u.ids.push_back(gi_probe->octree_buffer);
+ u.ids.push_back(voxel_gi->octree_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 2;
- u.ids.push_back(gi_probe->data_buffer);
+ u.ids.push_back(voxel_gi->data_buffer);
uniforms.push_back(u);
}
{
@@ -6355,24 +7183,24 @@ void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform &
uniforms.push_back(u);
}
- RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_sdf_shader_version_shader, 0);
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, voxel_gi_sdf_shader_version_shader, 0);
{
uint32_t push_constant[4] = { 0, 0, 0, 0 };
- for (int i = 0; i < gi_probe->level_counts.size() - 1; i++) {
- push_constant[0] += gi_probe->level_counts[i];
+ for (int i = 0; i < voxel_gi->level_counts.size() - 1; i++) {
+ push_constant[0] += voxel_gi->level_counts[i];
}
- push_constant[1] = push_constant[0] + gi_probe->level_counts[gi_probe->level_counts.size() - 1];
+ push_constant[1] = push_constant[0] + voxel_gi->level_counts[voxel_gi->level_counts.size() - 1];
print_line("offset: " + itos(push_constant[0]));
print_line("size: " + itos(push_constant[1]));
//create SDF
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_sdf_shader_pipeline);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, voxel_gi_sdf_shader_pipeline);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set, 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, push_constant, sizeof(uint32_t) * 4);
- RD::get_singleton()->compute_list_dispatch(compute_list, gi_probe->octree_size.x / 4, gi_probe->octree_size.y / 4, gi_probe->octree_size.z / 4);
+ RD::get_singleton()->compute_list_dispatch(compute_list, voxel_gi->octree_size.x / 4, voxel_gi->octree_size.y / 4, voxel_gi->octree_size.z / 4);
RD::get_singleton()->compute_list_end();
}
@@ -6382,232 +7210,206 @@ void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform &
#endif
}
- gi_probe->version++;
- gi_probe->data_version++;
+ voxel_gi->version++;
+ voxel_gi->data_version++;
- gi_probe->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
+ voxel_gi->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
}
-AABB RendererStorageRD::gi_probe_get_bounds(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, AABB());
+AABB RendererStorageRD::voxel_gi_get_bounds(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, AABB());
- return gi_probe->bounds;
+ return voxel_gi->bounds;
}
-Vector3i RendererStorageRD::gi_probe_get_octree_size(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, Vector3i());
- return gi_probe->octree_size;
+Vector3i RendererStorageRD::voxel_gi_get_octree_size(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, Vector3i());
+ return voxel_gi->octree_size;
}
-Vector<uint8_t> RendererStorageRD::gi_probe_get_octree_cells(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>());
+Vector<uint8_t> RendererStorageRD::voxel_gi_get_octree_cells(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>());
- if (gi_probe->octree_buffer.is_valid()) {
- return RD::get_singleton()->buffer_get_data(gi_probe->octree_buffer);
+ if (voxel_gi->octree_buffer.is_valid()) {
+ return RD::get_singleton()->buffer_get_data(voxel_gi->octree_buffer);
}
return Vector<uint8_t>();
}
-Vector<uint8_t> RendererStorageRD::gi_probe_get_data_cells(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>());
+Vector<uint8_t> RendererStorageRD::voxel_gi_get_data_cells(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>());
- if (gi_probe->data_buffer.is_valid()) {
- return RD::get_singleton()->buffer_get_data(gi_probe->data_buffer);
+ if (voxel_gi->data_buffer.is_valid()) {
+ return RD::get_singleton()->buffer_get_data(voxel_gi->data_buffer);
}
return Vector<uint8_t>();
}
-Vector<uint8_t> RendererStorageRD::gi_probe_get_distance_field(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>());
+Vector<uint8_t> RendererStorageRD::voxel_gi_get_distance_field(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>());
- if (gi_probe->data_buffer.is_valid()) {
- return RD::get_singleton()->texture_get_data(gi_probe->sdf_texture, 0);
+ if (voxel_gi->data_buffer.is_valid()) {
+ return RD::get_singleton()->texture_get_data(voxel_gi->sdf_texture, 0);
}
return Vector<uint8_t>();
}
-Vector<int> RendererStorageRD::gi_probe_get_level_counts(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, Vector<int>());
+Vector<int> RendererStorageRD::voxel_gi_get_level_counts(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, Vector<int>());
- return gi_probe->level_counts;
+ return voxel_gi->level_counts;
}
-Transform RendererStorageRD::gi_probe_get_to_cell_xform(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, Transform());
+Transform3D RendererStorageRD::voxel_gi_get_to_cell_xform(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, Transform3D());
- return gi_probe->to_cell_xform;
+ return voxel_gi->to_cell_xform;
}
-void RendererStorageRD::gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererStorageRD::voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->dynamic_range = p_range;
- gi_probe->version++;
+ voxel_gi->dynamic_range = p_range;
+ voxel_gi->version++;
}
-float RendererStorageRD::gi_probe_get_dynamic_range(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
+float RendererStorageRD::voxel_gi_get_dynamic_range(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
- return gi_probe->dynamic_range;
+ return voxel_gi->dynamic_range;
}
-void RendererStorageRD::gi_probe_set_propagation(RID p_gi_probe, float p_range) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererStorageRD::voxel_gi_set_propagation(RID p_voxel_gi, float p_range) {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->propagation = p_range;
- gi_probe->version++;
+ voxel_gi->propagation = p_range;
+ voxel_gi->version++;
}
-float RendererStorageRD::gi_probe_get_propagation(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->propagation;
+float RendererStorageRD::voxel_gi_get_propagation(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->propagation;
}
-void RendererStorageRD::gi_probe_set_energy(RID p_gi_probe, float p_energy) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererStorageRD::voxel_gi_set_energy(RID p_voxel_gi, float p_energy) {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->energy = p_energy;
+ voxel_gi->energy = p_energy;
}
-float RendererStorageRD::gi_probe_get_energy(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->energy;
+float RendererStorageRD::voxel_gi_get_energy(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->energy;
}
-void RendererStorageRD::gi_probe_set_ao(RID p_gi_probe, float p_ao) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererStorageRD::voxel_gi_set_bias(RID p_voxel_gi, float p_bias) {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->ao = p_ao;
+ voxel_gi->bias = p_bias;
}
-float RendererStorageRD::gi_probe_get_ao(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->ao;
+float RendererStorageRD::voxel_gi_get_bias(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->bias;
}
-void RendererStorageRD::gi_probe_set_ao_size(RID p_gi_probe, float p_strength) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererStorageRD::voxel_gi_set_normal_bias(RID p_voxel_gi, float p_normal_bias) {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->ao_size = p_strength;
+ voxel_gi->normal_bias = p_normal_bias;
}
-float RendererStorageRD::gi_probe_get_ao_size(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->ao_size;
+float RendererStorageRD::voxel_gi_get_normal_bias(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->normal_bias;
}
-void RendererStorageRD::gi_probe_set_bias(RID p_gi_probe, float p_bias) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererStorageRD::voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->bias = p_bias;
+ voxel_gi->anisotropy_strength = p_strength;
}
-float RendererStorageRD::gi_probe_get_bias(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->bias;
+float RendererStorageRD::voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->anisotropy_strength;
}
-void RendererStorageRD::gi_probe_set_normal_bias(RID p_gi_probe, float p_normal_bias) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererStorageRD::voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->normal_bias = p_normal_bias;
+ voxel_gi->interior = p_enable;
}
-float RendererStorageRD::gi_probe_get_normal_bias(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->normal_bias;
-}
-
-void RendererStorageRD::gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->anisotropy_strength = p_strength;
-}
+void RendererStorageRD::voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
-float RendererStorageRD::gi_probe_get_anisotropy_strength(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->anisotropy_strength;
+ voxel_gi->use_two_bounces = p_enable;
+ voxel_gi->version++;
}
-void RendererStorageRD::gi_probe_set_interior(RID p_gi_probe, bool p_enable) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->interior = p_enable;
+bool RendererStorageRD::voxel_gi_is_using_two_bounces(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, false);
+ return voxel_gi->use_two_bounces;
}
-void RendererStorageRD::gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->use_two_bounces = p_enable;
- gi_probe->version++;
+bool RendererStorageRD::voxel_gi_is_interior(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->interior;
}
-bool RendererStorageRD::gi_probe_is_using_two_bounces(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, false);
- return gi_probe->use_two_bounces;
+uint32_t RendererStorageRD::voxel_gi_get_version(RID p_voxel_gi) {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->version;
}
-bool RendererStorageRD::gi_probe_is_interior(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->interior;
+uint32_t RendererStorageRD::voxel_gi_get_data_version(RID p_voxel_gi) {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->data_version;
}
-uint32_t RendererStorageRD::gi_probe_get_version(RID p_gi_probe) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->version;
+RID RendererStorageRD::voxel_gi_get_octree_buffer(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, RID());
+ return voxel_gi->octree_buffer;
}
-uint32_t RendererStorageRD::gi_probe_get_data_version(RID p_gi_probe) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->data_version;
+RID RendererStorageRD::voxel_gi_get_data_buffer(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, RID());
+ return voxel_gi->data_buffer;
}
-RID RendererStorageRD::gi_probe_get_octree_buffer(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, RID());
- return gi_probe->octree_buffer;
-}
+RID RendererStorageRD::voxel_gi_get_sdf_texture(RID p_voxel_gi) {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, RID());
-RID RendererStorageRD::gi_probe_get_data_buffer(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, RID());
- return gi_probe->data_buffer;
-}
-
-RID RendererStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, RID());
-
- return gi_probe->sdf_texture;
+ return voxel_gi->sdf_texture;
}
/* LIGHTMAP API */
@@ -6621,20 +7423,20 @@ void RendererStorageRD::lightmap_initialize(RID p_lightmap) {
}
void RendererStorageRD::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) {
- Lightmap *lm = lightmap_owner.getornull(p_lightmap);
+ Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND(!lm);
lightmap_array_version++;
//erase lightmap users
if (lm->light_texture.is_valid()) {
- Texture *t = texture_owner.getornull(lm->light_texture);
+ Texture *t = texture_owner.get_or_null(lm->light_texture);
if (t) {
t->lightmap_users.erase(p_lightmap);
}
}
- Texture *t = texture_owner.getornull(p_light);
+ Texture *t = texture_owner.get_or_null(p_light);
lm->light_texture = p_light;
lm->uses_spherical_harmonics = p_uses_spherical_haromics;
@@ -6669,19 +7471,19 @@ void RendererStorageRD::lightmap_set_textures(RID p_lightmap, RID p_light, bool
}
void RendererStorageRD::lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) {
- Lightmap *lm = lightmap_owner.getornull(p_lightmap);
+ Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND(!lm);
lm->bounds = p_bounds;
}
void RendererStorageRD::lightmap_set_probe_interior(RID p_lightmap, bool p_interior) {
- Lightmap *lm = lightmap_owner.getornull(p_lightmap);
+ Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND(!lm);
lm->interior = p_interior;
}
void RendererStorageRD::lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) {
- Lightmap *lm = lightmap_owner.getornull(p_lightmap);
+ Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND(!lm);
if (p_points.size()) {
@@ -6697,26 +7499,26 @@ void RendererStorageRD::lightmap_set_probe_capture_data(RID p_lightmap, const Pa
}
PackedVector3Array RendererStorageRD::lightmap_get_probe_capture_points(RID p_lightmap) const {
- Lightmap *lm = lightmap_owner.getornull(p_lightmap);
+ Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND_V(!lm, PackedVector3Array());
return lm->points;
}
PackedColorArray RendererStorageRD::lightmap_get_probe_capture_sh(RID p_lightmap) const {
- Lightmap *lm = lightmap_owner.getornull(p_lightmap);
+ Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND_V(!lm, PackedColorArray());
return lm->point_sh;
}
PackedInt32Array RendererStorageRD::lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const {
- Lightmap *lm = lightmap_owner.getornull(p_lightmap);
+ Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND_V(!lm, PackedInt32Array());
return lm->tetrahedra;
}
PackedInt32Array RendererStorageRD::lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const {
- Lightmap *lm = lightmap_owner.getornull(p_lightmap);
+ Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND_V(!lm, PackedInt32Array());
return lm->bsp_tree;
}
@@ -6726,7 +7528,7 @@ void RendererStorageRD::lightmap_set_probe_capture_update_speed(float p_speed) {
}
void RendererStorageRD::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) {
- Lightmap *lm = lightmap_owner.getornull(p_lightmap);
+ Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND(!lm);
for (int i = 0; i < 9; i++) {
@@ -6776,13 +7578,13 @@ void RendererStorageRD::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_p
}
bool RendererStorageRD::lightmap_is_interior(RID p_lightmap) const {
- const Lightmap *lm = lightmap_owner.getornull(p_lightmap);
+ const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND_V(!lm, false);
return lm->interior;
}
AABB RendererStorageRD::lightmap_get_aabb(RID p_lightmap) const {
- const Lightmap *lm = lightmap_owner.getornull(p_lightmap);
+ const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND_V(!lm, AABB());
return lm->bounds;
}
@@ -6822,7 +7624,7 @@ void RendererStorageRD::_update_render_target(RenderTarget *rt) {
//create a placeholder until updated
rt->texture = texture_allocate();
texture_2d_placeholder_initialize(rt->texture);
- Texture *tex = texture_owner.getornull(rt->texture);
+ Texture *tex = texture_owner.get_or_null(rt->texture);
tex->is_render_target = true;
}
@@ -6843,9 +7645,13 @@ void RendererStorageRD::_update_render_target(RenderTarget *rt) {
rd_format.width = rt->size.width;
rd_format.height = rt->size.height;
rd_format.depth = 1;
- rd_format.array_layers = 1;
+ rd_format.array_layers = rt->view_count; // for stereo we create two (or more) layers, need to see if we can make fallback work like this too if we don't have multiview
rd_format.mipmaps = 1;
- rd_format.texture_type = RD::TEXTURE_TYPE_2D;
+ if (rd_format.array_layers > 1) { // why are we not using rt->texture_type ??
+ rd_format.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ } else {
+ rd_format.texture_type = RD::TEXTURE_TYPE_2D;
+ }
rd_format.samples = RD::TEXTURE_SAMPLES_1;
rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
rd_format.shareable_formats.push_back(rt->color_format);
@@ -6857,7 +7663,7 @@ void RendererStorageRD::_update_render_target(RenderTarget *rt) {
Vector<RID> fb_textures;
fb_textures.push_back(rt->color);
- rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures);
+ rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures, RenderingDevice::INVALID_ID, rt->view_count);
if (rt->framebuffer.is_null()) {
_clear_render_target(rt);
ERR_FAIL_COND(rt->framebuffer.is_null());
@@ -6865,7 +7671,7 @@ void RendererStorageRD::_update_render_target(RenderTarget *rt) {
{ //update texture
- Texture *tex = texture_owner.getornull(rt->texture);
+ Texture *tex = texture_owner.get_or_null(rt->texture);
//free existing textures
if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) {
@@ -6971,16 +7777,19 @@ void RendererStorageRD::render_target_set_position(RID p_render_target, int p_x,
//unused for this render target
}
-void RendererStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+void RendererStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
- rt->size.x = p_width;
- rt->size.y = p_height;
- _update_render_target(rt);
+ if (rt->size.x != p_width || rt->size.y != p_height || rt->view_count != p_view_count) {
+ rt->size.x = p_width;
+ rt->size.y = p_height;
+ rt->view_count = p_view_count;
+ _update_render_target(rt);
+ }
}
RID RendererStorageRD::render_target_get_texture(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
return rt->texture;
@@ -6990,53 +7799,53 @@ void RendererStorageRD::render_target_set_external_texture(RID p_render_target,
}
void RendererStorageRD::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
rt->flags[p_flag] = p_value;
_update_render_target(rt);
}
bool RendererStorageRD::render_target_was_used(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, false);
return rt->was_used;
}
void RendererStorageRD::render_target_set_as_unused(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
rt->was_used = false;
}
Size2 RendererStorageRD::render_target_get_size(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, Size2());
return rt->size;
}
RID RendererStorageRD::render_target_get_rd_framebuffer(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
return rt->framebuffer;
}
RID RendererStorageRD::render_target_get_rd_texture(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
return rt->color;
}
RID RendererStorageRD::render_target_get_rd_backbuffer(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
return rt->backbuffer;
}
RID RendererStorageRD::render_target_get_rd_backbuffer_framebuffer(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
if (!rt->backbuffer.is_valid()) {
@@ -7047,32 +7856,32 @@ RID RendererStorageRD::render_target_get_rd_backbuffer_framebuffer(RID p_render_
}
void RendererStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
rt->clear_requested = true;
rt->clear_color = p_clear_color;
}
bool RendererStorageRD::render_target_is_clear_requested(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, false);
return rt->clear_requested;
}
Color RendererStorageRD::render_target_get_clear_request_color(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, Color());
return rt->clear_color;
}
void RendererStorageRD::render_target_disable_clear_request(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
rt->clear_requested = false;
}
void RendererStorageRD::render_target_do_clear_request(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
if (!rt->clear_requested) {
return;
@@ -7085,7 +7894,7 @@ void RendererStorageRD::render_target_do_clear_request(RID p_render_target) {
}
void RendererStorageRD::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
if (rt->sdf_oversize == p_size && rt->sdf_scale == p_scale) {
return;
@@ -7127,14 +7936,28 @@ Rect2i RendererStorageRD::_render_target_get_sdf_rect(const RenderTarget *rt) co
}
Rect2i RendererStorageRD::render_target_get_sdf_rect(RID p_render_target) const {
- const RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ const RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, Rect2i());
return _render_target_get_sdf_rect(rt);
}
+void RendererStorageRD::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ rt->sdf_enabled = p_enabled;
+}
+
+bool RendererStorageRD::render_target_is_sdf_enabled(RID p_render_target) const {
+ const RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, false);
+
+ return rt->sdf_enabled;
+}
+
RID RendererStorageRD::render_target_get_sdf_texture(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
if (rt->sdf_buffer_read.is_null()) {
// no texture, create a dummy one for the 2D uniform set
@@ -7200,7 +8023,7 @@ void RendererStorageRD::_render_target_allocate_sdf(RenderTarget *rt) {
rt->process_size.x = MAX(rt->process_size.x, 1);
rt->process_size.y = MAX(rt->process_size.y, 1);
- tformat.format = RD::DATA_FORMAT_R16G16_UINT;
+ tformat.format = RD::DATA_FORMAT_R16G16_SINT;
tformat.width = rt->process_size.width;
tformat.height = rt->process_size.height;
tformat.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
@@ -7208,7 +8031,7 @@ void RendererStorageRD::_render_target_allocate_sdf(RenderTarget *rt) {
rt->sdf_buffer_process[0] = RD::get_singleton()->texture_create(tformat, RD::TextureView());
rt->sdf_buffer_process[1] = RD::get_singleton()->texture_create(tformat, RD::TextureView());
- tformat.format = RD::DATA_FORMAT_R16_UNORM;
+ tformat.format = RD::DATA_FORMAT_R16_SNORM;
tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView());
@@ -7269,7 +8092,7 @@ void RendererStorageRD::_render_target_clear_sdf(RenderTarget *rt) {
}
RID RendererStorageRD::render_target_get_sdf_framebuffer(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
if (rt->sdf_buffer_write_fb.is_null()) {
@@ -7279,7 +8102,7 @@ RID RendererStorageRD::render_target_get_sdf_framebuffer(RID p_render_target) {
return rt->sdf_buffer_write_fb;
}
void RendererStorageRD::render_target_sdf_process(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
ERR_FAIL_COND(rt->sdf_buffer_write_fb.is_null());
@@ -7354,7 +8177,7 @@ void RendererStorageRD::render_target_sdf_process(RID p_render_target) {
}
void RendererStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
if (!rt->backbuffer.is_valid()) {
_create_render_target_backbuffer(rt);
@@ -7372,7 +8195,7 @@ void RendererStorageRD::render_target_copy_to_back_buffer(RID p_render_target, c
//single texture copy for backbuffer
//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_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, true, true);
+ effects->copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, true, true);
if (!p_gen_mipmaps) {
return;
@@ -7388,13 +8211,13 @@ void RendererStorageRD::render_target_copy_to_back_buffer(RID p_render_target, c
region.size.y = MAX(1, region.size.y >> 1);
const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i];
- effects.gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true);
+ effects->gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true);
prev_texture = mm.mipmap;
}
}
void RendererStorageRD::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
if (!rt->backbuffer.is_valid()) {
_create_render_target_backbuffer(rt);
@@ -7411,11 +8234,11 @@ void RendererStorageRD::render_target_clear_back_buffer(RID p_render_target, con
}
//single texture copy for backbuffer
- effects.set_color(rt->backbuffer_mipmap0, p_color, region, true);
+ effects->set_color(rt->backbuffer_mipmap0, p_color, region, true);
}
void RendererStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
if (!rt->backbuffer.is_valid()) {
_create_render_target_backbuffer(rt);
@@ -7441,69 +8264,75 @@ void RendererStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_targe
region.size.y = MAX(1, region.size.y >> 1);
const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i];
- effects.gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true);
+ effects->gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true);
prev_texture = mm.mipmap;
}
}
RID RendererStorageRD::render_target_get_framebuffer_uniform_set(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
return rt->framebuffer_uniform_set;
}
RID RendererStorageRD::render_target_get_backbuffer_uniform_set(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
return rt->backbuffer_uniform_set;
}
void RendererStorageRD::render_target_set_framebuffer_uniform_set(RID p_render_target, RID p_uniform_set) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
rt->framebuffer_uniform_set = p_uniform_set;
}
void RendererStorageRD::render_target_set_backbuffer_uniform_set(RID p_render_target, RID p_uniform_set) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
rt->backbuffer_uniform_set = p_uniform_set;
}
void RendererStorageRD::base_update_dependency(RID p_base, DependencyTracker *p_instance) {
if (mesh_owner.owns(p_base)) {
- Mesh *mesh = mesh_owner.getornull(p_base);
+ Mesh *mesh = mesh_owner.get_or_null(p_base);
p_instance->update_dependency(&mesh->dependency);
} else if (multimesh_owner.owns(p_base)) {
- MultiMesh *multimesh = multimesh_owner.getornull(p_base);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_base);
p_instance->update_dependency(&multimesh->dependency);
if (multimesh->mesh.is_valid()) {
base_update_dependency(multimesh->mesh, p_instance);
}
} else if (reflection_probe_owner.owns(p_base)) {
- ReflectionProbe *rp = reflection_probe_owner.getornull(p_base);
+ ReflectionProbe *rp = reflection_probe_owner.get_or_null(p_base);
p_instance->update_dependency(&rp->dependency);
} else if (decal_owner.owns(p_base)) {
- Decal *decal = decal_owner.getornull(p_base);
+ Decal *decal = decal_owner.get_or_null(p_base);
p_instance->update_dependency(&decal->dependency);
- } else if (gi_probe_owner.owns(p_base)) {
- GIProbe *gip = gi_probe_owner.getornull(p_base);
+ } else if (voxel_gi_owner.owns(p_base)) {
+ VoxelGI *gip = voxel_gi_owner.get_or_null(p_base);
p_instance->update_dependency(&gip->dependency);
} else if (lightmap_owner.owns(p_base)) {
- Lightmap *lm = lightmap_owner.getornull(p_base);
+ Lightmap *lm = lightmap_owner.get_or_null(p_base);
p_instance->update_dependency(&lm->dependency);
} else if (light_owner.owns(p_base)) {
- Light *l = light_owner.getornull(p_base);
+ Light *l = light_owner.get_or_null(p_base);
p_instance->update_dependency(&l->dependency);
} else if (particles_owner.owns(p_base)) {
- Particles *p = particles_owner.getornull(p_base);
+ Particles *p = particles_owner.get_or_null(p_base);
p_instance->update_dependency(&p->dependency);
} else if (particles_collision_owner.owns(p_base)) {
- ParticlesCollision *pc = particles_collision_owner.getornull(p_base);
+ ParticlesCollision *pc = particles_collision_owner.get_or_null(p_base);
p_instance->update_dependency(&pc->dependency);
+ } else if (fog_volume_owner.owns(p_base)) {
+ FogVolume *fv = fog_volume_owner.get_or_null(p_base);
+ p_instance->update_dependency(&fv->dependency);
+ } else if (visibility_notifier_owner.owns(p_base)) {
+ VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_base);
+ p_instance->update_dependency(&vn->dependency);
}
}
void RendererStorageRD::skeleton_update_dependency(RID p_skeleton, DependencyTracker *p_instance) {
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
ERR_FAIL_COND(!skeleton);
p_instance->update_dependency(&skeleton->dependency);
@@ -7522,8 +8351,8 @@ RS::InstanceType RendererStorageRD::get_base_type(RID p_rid) const {
if (decal_owner.owns(p_rid)) {
return RS::INSTANCE_DECAL;
}
- if (gi_probe_owner.owns(p_rid)) {
- return RS::INSTANCE_GI_PROBE;
+ if (voxel_gi_owner.owns(p_rid)) {
+ return RS::INSTANCE_VOXEL_GI;
}
if (light_owner.owns(p_rid)) {
return RS::INSTANCE_LIGHT;
@@ -7537,6 +8366,12 @@ RS::InstanceType RendererStorageRD::get_base_type(RID p_rid) const {
if (particles_collision_owner.owns(p_rid)) {
return RS::INSTANCE_PARTICLES_COLLISION;
}
+ if (fog_volume_owner.owns(p_rid)) {
+ return RS::INSTANCE_FOG_VOLUME;
+ }
+ if (visibility_notifier_owner.owns(p_rid)) {
+ return RS::INSTANCE_VISIBLITY_NOTIFIER;
+ }
return RS::INSTANCE_NONE;
}
@@ -7606,7 +8441,7 @@ void RendererStorageRD::_update_decal_atlas() {
while ((K = decal_atlas.textures.next(K))) {
DecalAtlas::SortItem &si = itemsv.write[idx];
- Texture *src_tex = texture_owner.getornull(*K);
+ Texture *src_tex = texture_owner.get_or_null(*K);
si.size.width = (src_tex->width / border) + 1;
si.size.height = (src_tex->height / border) + 1;
@@ -7755,15 +8590,15 @@ void RendererStorageRD::_update_decal_atlas() {
const RID *K = nullptr;
while ((K = decal_atlas.textures.next(K))) {
DecalAtlas::Texture *t = decal_atlas.textures.getptr(*K);
- Texture *src_tex = texture_owner.getornull(*K);
- effects.copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list, false, t->panorama_to_dp_users > 0);
+ Texture *src_tex = texture_owner.get_or_null(*K);
+ effects->copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list, false, t->panorama_to_dp_users > 0);
}
RD::get_singleton()->draw_list_end();
prev_texture = mm.texture;
} else {
- effects.copy_to_fb_rect(prev_texture, mm.fb, Rect2i(Point2i(), mm.size));
+ effects->copy_to_fb_rect(prev_texture, mm.fb, Rect2i(Point2i(), mm.size));
prev_texture = mm.texture;
}
} else {
@@ -8047,7 +8882,7 @@ void RendererStorageRD::_global_variable_store_in_buffer(int32_t p_index, RS::Gl
} break;
case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
GlobalVariables::Value *bv = &global_variables.buffer_values[p_index];
- Transform v = p_value;
+ Transform3D v = p_value;
bv[0].x = v.basis.elements[0][0];
bv[0].y = v.basis.elements[1][0];
bv[0].z = v.basis.elements[2][0];
@@ -8171,7 +9006,7 @@ void RendererStorageRD::global_variable_set(const StringName &p_name, const Vari
} else {
//texture
for (Set<RID>::Element *E = gv.texture_materials.front(); E; E = E->next()) {
- Material *material = material_owner.getornull(E->get());
+ Material *material = material_owner.get_or_null(E->get());
ERR_CONTINUE(!material);
_material_queue_update(material, false, true);
}
@@ -8183,6 +9018,9 @@ void RendererStorageRD::global_variable_set_override(const StringName &p_name, c
if (!global_variables.variables.has(p_name)) {
return; //variable may not exist
}
+
+ ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT);
+
GlobalVariables::Variable &gv = global_variables.variables[p_name];
gv.override = p_value;
@@ -8199,7 +9037,7 @@ void RendererStorageRD::global_variable_set_override(const StringName &p_name, c
} else {
//texture
for (Set<RID>::Element *E = gv.texture_materials.front(); E; E = E->next()) {
- Material *material = material_owner.getornull(E->get());
+ Material *material = material_owner.get_or_null(E->get());
ERR_CONTINUE(!material);
_material_queue_update(material, false, true);
}
@@ -8238,10 +9076,10 @@ void RendererStorageRD::global_variables_load_settings(bool p_load_textures) {
List<PropertyInfo> settings;
ProjectSettings::get_singleton()->get_property_list(&settings);
- for (List<PropertyInfo>::Element *E = settings.front(); E; E = E->next()) {
- if (E->get().name.begins_with("shader_globals/")) {
- StringName name = E->get().name.get_slice("/", 1);
- Dictionary d = ProjectSettings::get_singleton()->get(E->get().name);
+ for (const PropertyInfo &E : settings) {
+ if (E.name.begins_with("shader_globals/")) {
+ StringName name = E.name.get_slice("/", 1);
+ Dictionary d = ProjectSettings::get_singleton()->get(E.name);
ERR_CONTINUE(!d.has("type"));
ERR_CONTINUE(!d.has("value"));
@@ -8380,7 +9218,7 @@ void RendererStorageRD::global_variables_instance_update(RID p_instance, int p_i
pos += p_index;
- _fill_std140_variant_ubo_value(datatype, p_value, (uint8_t *)&global_variables.buffer_values[pos], true); //instances always use linear color in this renderer
+ _fill_std140_variant_ubo_value(datatype, 0, p_value, (uint8_t *)&global_variables.buffer_values[pos], true); //instances always use linear color in this renderer
_global_variable_mark_buffer_dirty(pos, 1);
}
@@ -8409,8 +9247,8 @@ void RendererStorageRD::_update_global_variables() {
if (global_variables.must_update_buffer_materials) {
// only happens in the case of a buffer variable added or removed,
// so not often.
- for (List<RID>::Element *E = global_variables.materials_using_buffer.front(); E; E = E->next()) {
- Material *material = material_owner.getornull(E->get());
+ for (const RID &E : global_variables.materials_using_buffer) {
+ Material *material = material_owner.get_or_null(E);
ERR_CONTINUE(!material); //wtf
_material_queue_update(material, true, false);
@@ -8422,8 +9260,8 @@ void RendererStorageRD::_update_global_variables() {
if (global_variables.must_update_texture_materials) {
// only happens in the case of a buffer variable added or removed,
// so not often.
- for (List<RID>::Element *E = global_variables.materials_using_texture.front(); E; E = E->next()) {
- Material *material = material_owner.getornull(E->get());
+ for (const RID &E : global_variables.materials_using_texture) {
+ Material *material = material_owner.get_or_null(E);
ERR_CONTINUE(!material); //wtf
_material_queue_update(material, false, true);
@@ -8468,8 +9306,9 @@ bool RendererStorageRD::has_os_feature(const String &p_feature) const {
bool RendererStorageRD::free(RID p_rid) {
if (texture_owner.owns(p_rid)) {
- Texture *t = texture_owner.getornull(p_rid);
+ Texture *t = texture_owner.get_or_null(p_rid);
+ ERR_FAIL_COND_V(!t, false);
ERR_FAIL_COND_V(t->is_render_target, false);
if (RD::get_singleton()->texture_is_valid(t->rd_texture_srgb)) {
@@ -8481,7 +9320,7 @@ bool RendererStorageRD::free(RID p_rid) {
}
if (t->is_proxy && t->proxy_to.is_valid()) {
- Texture *proxy_to = texture_owner.getornull(t->proxy_to);
+ Texture *proxy_to = texture_owner.get_or_null(t->proxy_to);
if (proxy_to) {
proxy_to->proxies.erase(p_rid);
}
@@ -8493,7 +9332,7 @@ bool RendererStorageRD::free(RID p_rid) {
}
for (int i = 0; i < t->proxies.size(); i++) {
- Texture *p = texture_owner.getornull(t->proxies[i]);
+ Texture *p = texture_owner.get_or_null(t->proxies[i]);
ERR_CONTINUE(!p);
p->proxy_to = RID();
p->rd_texture = RID();
@@ -8506,11 +9345,9 @@ bool RendererStorageRD::free(RID p_rid) {
texture_owner.free(p_rid);
} else if (canvas_texture_owner.owns(p_rid)) {
- CanvasTexture *ct = canvas_texture_owner.getornull(p_rid);
- memdelete(ct);
canvas_texture_owner.free(p_rid);
} else if (shader_owner.owns(p_rid)) {
- Shader *shader = shader_owner.getornull(p_rid);
+ Shader *shader = shader_owner.get_or_null(p_rid);
//make material unreference this
while (shader->owners.size()) {
material_set_shader(shader->owners.front()->get()->self, RID());
@@ -8522,10 +9359,7 @@ bool RendererStorageRD::free(RID p_rid) {
shader_owner.free(p_rid);
} else if (material_owner.owns(p_rid)) {
- Material *material = material_owner.getornull(p_rid);
- if (material->update_requested) {
- _update_queued_materials();
- }
+ Material *material = material_owner.get_or_null(p_rid);
material_set_shader(p_rid, RID()); //clean up shader
material->dependency.deleted_notify(p_rid);
@@ -8533,7 +9367,7 @@ bool RendererStorageRD::free(RID p_rid) {
} else if (mesh_owner.owns(p_rid)) {
mesh_clear(p_rid);
mesh_set_shadow_mesh(p_rid, RID());
- Mesh *mesh = mesh_owner.getornull(p_rid);
+ Mesh *mesh = mesh_owner.get_or_null(p_rid);
mesh->dependency.deleted_notify(p_rid);
if (mesh->instances.size()) {
ERR_PRINT("deleting mesh with active instances");
@@ -8547,32 +9381,31 @@ bool RendererStorageRD::free(RID p_rid) {
}
mesh_owner.free(p_rid);
} else if (mesh_instance_owner.owns(p_rid)) {
- MeshInstance *mi = mesh_instance_owner.getornull(p_rid);
+ MeshInstance *mi = mesh_instance_owner.get_or_null(p_rid);
_mesh_instance_clear(mi);
mi->mesh->instances.erase(mi->I);
mi->I = nullptr;
mesh_instance_owner.free(p_rid);
- memdelete(mi);
} else if (multimesh_owner.owns(p_rid)) {
_update_dirty_multimeshes();
multimesh_allocate_data(p_rid, 0, RS::MULTIMESH_TRANSFORM_2D);
- MultiMesh *multimesh = multimesh_owner.getornull(p_rid);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_rid);
multimesh->dependency.deleted_notify(p_rid);
multimesh_owner.free(p_rid);
} else if (skeleton_owner.owns(p_rid)) {
_update_dirty_skeletons();
skeleton_allocate_data(p_rid, 0);
- Skeleton *skeleton = skeleton_owner.getornull(p_rid);
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_rid);
skeleton->dependency.deleted_notify(p_rid);
skeleton_owner.free(p_rid);
} else if (reflection_probe_owner.owns(p_rid)) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid);
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_rid);
reflection_probe->dependency.deleted_notify(p_rid);
reflection_probe_owner.free(p_rid);
} else if (decal_owner.owns(p_rid)) {
- Decal *decal = decal_owner.getornull(p_rid);
+ Decal *decal = decal_owner.get_or_null(p_rid);
for (int i = 0; i < RS::DECAL_TEXTURE_MAX; i++) {
if (decal->textures[i].is_valid() && texture_owner.owns(decal->textures[i])) {
texture_remove_from_decal_atlas(decal->textures[i]);
@@ -8580,47 +9413,55 @@ bool RendererStorageRD::free(RID p_rid) {
}
decal->dependency.deleted_notify(p_rid);
decal_owner.free(p_rid);
- } else if (gi_probe_owner.owns(p_rid)) {
- gi_probe_allocate_data(p_rid, Transform(), AABB(), Vector3i(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<int>()); //deallocate
- GIProbe *gi_probe = gi_probe_owner.getornull(p_rid);
- gi_probe->dependency.deleted_notify(p_rid);
- gi_probe_owner.free(p_rid);
+ } else if (voxel_gi_owner.owns(p_rid)) {
+ voxel_gi_allocate_data(p_rid, Transform3D(), AABB(), Vector3i(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<int>()); //deallocate
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_rid);
+ voxel_gi->dependency.deleted_notify(p_rid);
+ voxel_gi_owner.free(p_rid);
} else if (lightmap_owner.owns(p_rid)) {
lightmap_set_textures(p_rid, RID(), false);
- Lightmap *lightmap = lightmap_owner.getornull(p_rid);
+ Lightmap *lightmap = lightmap_owner.get_or_null(p_rid);
lightmap->dependency.deleted_notify(p_rid);
lightmap_owner.free(p_rid);
} else if (light_owner.owns(p_rid)) {
light_set_projector(p_rid, RID()); //clear projector
// delete the texture
- Light *light = light_owner.getornull(p_rid);
+ Light *light = light_owner.get_or_null(p_rid);
light->dependency.deleted_notify(p_rid);
light_owner.free(p_rid);
} else if (particles_owner.owns(p_rid)) {
update_particles();
- Particles *particles = particles_owner.getornull(p_rid);
+ Particles *particles = particles_owner.get_or_null(p_rid);
particles->dependency.deleted_notify(p_rid);
_particles_free_data(particles);
particles_owner.free(p_rid);
} else if (particles_collision_owner.owns(p_rid)) {
- ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_rid);
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_rid);
if (particles_collision->heightfield_texture.is_valid()) {
RD::get_singleton()->free(particles_collision->heightfield_texture);
}
particles_collision->dependency.deleted_notify(p_rid);
particles_collision_owner.free(p_rid);
+ } else if (visibility_notifier_owner.owns(p_rid)) {
+ VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_rid);
+ vn->dependency.deleted_notify(p_rid);
+ visibility_notifier_owner.free(p_rid);
} else if (particles_collision_instance_owner.owns(p_rid)) {
particles_collision_instance_owner.free(p_rid);
+ } else if (fog_volume_owner.owns(p_rid)) {
+ FogVolume *fog_volume = fog_volume_owner.get_or_null(p_rid);
+ fog_volume->dependency.deleted_notify(p_rid);
+ fog_volume_owner.free(p_rid);
} else if (render_target_owner.owns(p_rid)) {
- RenderTarget *rt = render_target_owner.getornull(p_rid);
+ RenderTarget *rt = render_target_owner.get_or_null(p_rid);
_clear_render_target(rt);
if (rt->texture.is_valid()) {
- Texture *tex = texture_owner.getornull(rt->texture);
+ Texture *tex = texture_owner.get_or_null(rt->texture);
tex->is_render_target = false;
free(rt->texture);
}
@@ -8633,8 +9474,13 @@ bool RendererStorageRD::free(RID p_rid) {
return true;
}
+void RendererStorageRD::init_effects(bool p_prefer_raster_effects) {
+ effects = memnew(EffectsRD(p_prefer_raster_effects));
+}
+
EffectsRD *RendererStorageRD::get_effects() {
- return &effects;
+ ERR_FAIL_NULL_V_MSG(effects, nullptr, "Effects haven't been initialised yet.");
+ return effects;
}
void RendererStorageRD::capture_timestamps_begin() {
@@ -8665,6 +9511,29 @@ String RendererStorageRD::get_captured_timestamp_name(uint32_t p_index) const {
return RD::get_singleton()->get_captured_timestamp_name(p_index);
}
+void RendererStorageRD::update_memory_info() {
+ texture_mem_cache = RenderingDevice::get_singleton()->get_memory_usage(RenderingDevice::MEMORY_TEXTURES);
+ buffer_mem_cache = RenderingDevice::get_singleton()->get_memory_usage(RenderingDevice::MEMORY_BUFFERS);
+ total_mem_cache = RenderingDevice::get_singleton()->get_memory_usage(RenderingDevice::MEMORY_TOTAL);
+}
+uint64_t RendererStorageRD::get_rendering_info(RS::RenderingInfo p_info) {
+ if (p_info == RS::RENDERING_INFO_TEXTURE_MEM_USED) {
+ return texture_mem_cache;
+ } else if (p_info == RS::RENDERING_INFO_BUFFER_MEM_USED) {
+ return buffer_mem_cache;
+ } else if (p_info == RS::RENDERING_INFO_VIDEO_MEM_USED) {
+ return total_mem_cache;
+ }
+ return 0;
+}
+
+String RendererStorageRD::get_video_adapter_name() const {
+ return RenderingDevice::get_singleton()->get_device_name();
+}
+String RendererStorageRD::get_video_adapter_vendor() const {
+ return RenderingDevice::get_singleton()->get_device_vendor_name();
+}
+
RendererStorageRD *RendererStorageRD::base_singleton = nullptr;
RendererStorageRD::RendererStorageRD() {
@@ -8685,7 +9554,6 @@ RendererStorageRD::RendererStorageRD() {
memset(global_variables.buffer_dirty_regions, 0, sizeof(bool) * global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE);
global_variables.buffer = RD::get_singleton()->storage_buffer_create(sizeof(GlobalVariables::Value) * global_variables.buffer_size);
- material_update_list = nullptr;
{ //create default textures
RD::TextureFormat tformat;
@@ -8883,6 +9751,18 @@ RendererStorageRD::RendererStorageRD() {
{
Vector<Vector<uint8_t>> vpv;
vpv.push_back(pv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_3D_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+ for (int i = 0; i < 64; i++) {
+ pv.set(i * 4 + 0, 255);
+ pv.set(i * 4 + 1, 255);
+ pv.set(i * 4 + 2, 255);
+ pv.set(i * 4 + 3, 255);
+ }
+
+ {
+ Vector<Vector<uint8_t>> vpv;
+ vpv.push_back(pv);
default_rd_textures[DEFAULT_RD_TEXTURE_3D_WHITE] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
}
}
@@ -8930,26 +9810,42 @@ RendererStorageRD::RendererStorageRD() {
} break;
case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
} break;
case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
} break;
case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: {
sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
sampler_state.use_anisotropy = true;
sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
} 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;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
sampler_state.use_anisotropy = true;
sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
@@ -8982,6 +9878,9 @@ RendererStorageRD::RendererStorageRD() {
}
}
+ //custom sampler
+ sampler_rd_configure_custom(0.0f);
+
//default rd buffers
{
Vector<uint8_t> buffer;
@@ -9096,15 +9995,6 @@ RendererStorageRD::RendererStorageRD() {
}
}
- {
- Vector<String> sdf_versions;
- sdf_versions.push_back(""); //one only
- giprobe_sdf_shader.initialize(sdf_versions);
- giprobe_sdf_shader_version = giprobe_sdf_shader.version_create();
- giprobe_sdf_shader_version_shader = giprobe_sdf_shader.version_get_shader(giprobe_sdf_shader_version, 0);
- giprobe_sdf_shader_pipeline = RD::get_singleton()->compute_pipeline_create(giprobe_sdf_shader_version_shader);
- }
-
using_lightmap_array = true; // high end
if (using_lightmap_array) {
uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
@@ -9143,7 +10033,10 @@ RendererStorageRD::RendererStorageRD() {
actions.renames["RESTART"] = "restart";
actions.renames["CUSTOM"] = "PARTICLE.custom";
actions.renames["TRANSFORM"] = "PARTICLE.xform";
- actions.renames["TIME"] = "FRAME.time";
+ actions.renames["TIME"] = "frame_history.data[0].time";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
actions.renames["LIFETIME"] = "params.lifetime";
actions.renames["DELTA"] = "local_delta";
actions.renames["NUMBER"] = "particle_number";
@@ -9189,7 +10082,15 @@ RendererStorageRD::RendererStorageRD() {
// default material and shader for particles shader
particles_shader.default_shader = shader_allocate();
shader_initialize(particles_shader.default_shader);
- shader_set_code(particles_shader.default_shader, "shader_type particles; void process() { COLOR = vec4(1.0); } \n");
+ shader_set_code(particles_shader.default_shader, R"(
+// Default particles shader.
+
+shader_type particles;
+
+void process() {
+ COLOR = vec4(1.0);
+}
+)");
particles_shader.default_material = material_allocate();
material_initialize(particles_shader.default_material);
material_set_shader(particles_shader.default_material, particles_shader.default_shader);
@@ -9310,12 +10211,20 @@ RendererStorageRD::~RendererStorageRD() {
}
}
+ //custom samplers
+ for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
+ for (int j = 0; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
+ if (custom_rd_samplers[i][j].is_valid()) {
+ RD::get_singleton()->free(custom_rd_samplers[i][j]);
+ }
+ }
+ }
+
//def buffers
for (int i = 0; i < DEFAULT_RD_BUFFER_MAX; i++) {
RD::get_singleton()->free(mesh_default_rd_buffers[i]);
}
- giprobe_sdf_shader.version_free(giprobe_sdf_shader_version);
particles_shader.copy_shader.version_free(particles_shader.copy_shader_version);
rt_sdf.shader.version_free(rt_sdf.shader_version);
@@ -9333,4 +10242,9 @@ RendererStorageRD::~RendererStorageRD() {
if (decal_atlas.texture.is_valid()) {
RD::get_singleton()->free(decal_atlas.texture);
}
+
+ if (effects) {
+ memdelete(effects);
+ effects = nullptr;
+ }
}
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h
index 49f7f3dba6..9a64480c3e 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.h
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.h
@@ -38,15 +38,15 @@
#include "servers/rendering/renderer_rd/effects_rd.h"
#include "servers/rendering/renderer_rd/shader_compiler_rd.h"
#include "servers/rendering/renderer_rd/shaders/canvas_sdf.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/particles.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/particles_copy.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/skeleton.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
class RendererStorageRD : public RendererStorage {
public:
- static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_array) {
+ static _FORCE_INLINE_ void store_transform(const Transform3D &p_mtx, float *p_array) {
p_array[0] = p_mtx.basis.elements[0][0];
p_array[1] = p_mtx.basis.elements[1][0];
p_array[2] = p_mtx.basis.elements[2][0];
@@ -95,7 +95,7 @@ public:
p_array[11] = 0;
}
- static _FORCE_INLINE_ void store_transform_transposed_3x4(const Transform &p_mtx, float *p_array) {
+ static _FORCE_INLINE_ void store_transform_transposed_3x4(const Transform3D &p_mtx, float *p_array) {
p_array[0] = p_mtx.basis.elements[0][0];
p_array[1] = p_mtx.basis.elements[0][1];
p_array[2] = p_mtx.basis.elements[0][2];
@@ -129,12 +129,13 @@ public:
SHADER_TYPE_3D,
SHADER_TYPE_PARTICLES,
SHADER_TYPE_SKY,
+ SHADER_TYPE_FOG,
SHADER_TYPE_MAX
};
struct ShaderData {
virtual void set_code(const String &p_Code) = 0;
- virtual void set_default_texture_param(const StringName &p_name, RID p_texture) = 0;
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) = 0;
virtual void get_param_list(List<PropertyInfo> *p_param_list) const = 0;
virtual void get_instance_param_list(List<InstanceShaderParam> *p_param_list) const = 0;
@@ -151,13 +152,17 @@ public:
struct MaterialData {
void update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color);
- void update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color);
+ void update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, Map<int, RID>> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color);
virtual void set_render_priority(int p_priority) = 0;
virtual void set_next_pass(RID p_pass) = 0;
- virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) = 0;
+ virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) = 0;
virtual ~MaterialData();
+ //to be used internally by update_parameters, in the most common configuration of material parameters
+ bool update_parameters_uniform_set(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, const Map<StringName, Map<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier = RD::BARRIER_MASK_ALL);
+ void free_parameters_uniform_set(RID p_uniform_set);
+
private:
friend class RendererStorageRD;
RID self;
@@ -165,8 +170,14 @@ public:
List<RID>::Element *global_texture_E = nullptr;
uint64_t global_textures_pass = 0;
Map<StringName, uint64_t> used_global_textures;
+
+ //internally by update_parameters_uniform_set
+ Vector<uint8_t> ubo_data;
+ RID uniform_buffer;
+ Vector<RID> texture_cache;
};
typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *);
+ static void _material_uniform_set_erased(const RID &p_set, void *p_material);
enum DefaultRDTexture {
DEFAULT_RD_TEXTURE_WHITE,
@@ -178,6 +189,7 @@ public:
DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK,
DEFAULT_RD_TEXTURE_CUBEMAP_WHITE,
DEFAULT_RD_TEXTURE_3D_WHITE,
+ DEFAULT_RD_TEXTURE_3D_BLACK,
DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE,
DEFAULT_RD_TEXTURE_2D_UINT,
DEFAULT_RD_TEXTURE_MAX
@@ -221,7 +233,7 @@ private:
~CanvasTexture();
};
- RID_PtrOwner<CanvasTexture, true> canvas_texture_owner;
+ RID_Owner<CanvasTexture, true> canvas_texture_owner;
/* TEXTURE API */
struct Texture {
@@ -308,6 +320,7 @@ private:
RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX];
RID default_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
+ RID custom_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
RID default_rd_storage_buffer;
/* DECAL ATLAS */
@@ -362,7 +375,7 @@ private:
ShaderData *data;
String code;
ShaderType type;
- Map<StringName, RID> default_texture_parameter;
+ Map<StringName, Map<int, RID>> default_texture_parameter;
Set<Material *> owners;
};
@@ -373,25 +386,28 @@ private:
struct Material {
RID self;
- MaterialData *data;
- Shader *shader;
+ MaterialData *data = nullptr;
+ Shader *shader = nullptr;
//shortcut to shader data and type
- ShaderType shader_type;
+ ShaderType shader_type = SHADER_TYPE_MAX;
uint32_t shader_id = 0;
- bool update_requested;
- bool uniform_dirty;
- bool texture_dirty;
- Material *update_next;
+ bool uniform_dirty = false;
+ bool texture_dirty = false;
Map<StringName, Variant> params;
- int32_t priority;
+ int32_t priority = 0;
RID next_pass;
+ SelfList<Material> update_element;
+
Dependency dependency;
+
+ Material() :
+ update_element(this) {}
};
MaterialDataRequestFunction material_data_request_func[SHADER_TYPE_MAX];
mutable RID_Owner<Material, true> material_owner;
- Material *material_update_list;
+ SelfList<Material>::List material_update_list;
void _material_queue_update(Material *material, bool p_uniform, bool p_texture);
void _update_queued_materials();
@@ -434,6 +450,7 @@ private:
struct LOD {
float edge_length = 0.0;
+ uint32_t index_count = 0;
RID index_buffer;
RID index_array;
};
@@ -513,7 +530,7 @@ private:
void _mesh_instance_clear(MeshInstance *mi);
void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
- mutable RID_PtrOwner<MeshInstance> mesh_instance_owner;
+ mutable RID_Owner<MeshInstance> mesh_instance_owner;
SelfList<MeshInstance>::List dirty_mesh_instance_weights;
SelfList<MeshInstance>::List dirty_mesh_instance_arrays;
@@ -607,7 +624,6 @@ private:
float color[4];
float custom[3];
float lifetime;
- uint32_t pad[3];
};
struct ParticlesFrameParams {
@@ -638,7 +654,9 @@ private:
COLLISION_TYPE_SPHERE,
COLLISION_TYPE_BOX,
COLLISION_TYPE_SDF,
- COLLISION_TYPE_HEIGHT_FIELD
+ COLLISION_TYPE_HEIGHT_FIELD,
+ COLLISION_TYPE_2D_SDF,
+
};
struct Collider {
@@ -647,7 +665,7 @@ private:
uint32_t type;
uint32_t texture_index; //texture index for vector field
- float scale;
+ real_t scale;
uint32_t pad[2];
};
@@ -656,8 +674,8 @@ private:
float prev_system_phase;
uint32_t cycle;
- float explosiveness;
- float randomness;
+ real_t explosiveness;
+ real_t randomness;
float time;
float delta;
@@ -699,17 +717,24 @@ private:
struct Particles {
RS::ParticlesMode mode = RS::PARTICLES_MODE_3D;
bool inactive = true;
- float inactive_time = 0.0;
+ double inactive_time = 0.0;
bool emitting = false;
bool one_shot = false;
int amount = 0;
- float lifetime = 1.0;
- float pre_process_time = 0.0;
- float explosiveness = 0.0;
- float randomness = 0.0;
+ double lifetime = 1.0;
+ double pre_process_time = 0.0;
+ real_t explosiveness = 0.0;
+ real_t randomness = 0.0;
bool restart_request = false;
AABB custom_aabb = AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8));
bool use_local_coords = true;
+ bool has_collision_cache = false;
+
+ bool has_sdf_collision = false;
+ Transform2D sdf_collision_transform;
+ Rect2 sdf_collision_to_screen;
+ RID sdf_collision_texture;
+
RID process_material;
uint32_t frame_counter = 0;
RS::ParticlesTransformAlign transform_align = RS::PARTICLES_TRANSFORM_ALIGN_DISABLED;
@@ -717,7 +742,7 @@ private:
RS::ParticlesDrawOrder draw_order = RS::PARTICLES_DRAW_ORDER_INDEX;
Vector<RID> draw_passes;
- Vector<Transform> trail_bind_poses;
+ Vector<Transform3D> trail_bind_poses;
bool trail_bind_poses_dirty = false;
RID trail_bind_pose_buffer;
RID trail_bind_pose_uniform_set;
@@ -743,26 +768,26 @@ private:
RID sub_emitter;
- float phase = 0.0;
- float prev_phase = 0.0;
+ double phase = 0.0;
+ double prev_phase = 0.0;
uint64_t prev_ticks = 0;
uint32_t random_seed = 0;
uint32_t cycle_number = 0;
- float speed_scale = 1.0;
+ double speed_scale = 1.0;
int fixed_fps = 30;
bool interpolate = true;
bool fractional_delta = false;
- float frame_remainder = 0;
- float collision_base_size = 0.01;
+ double frame_remainder = 0;
+ real_t collision_base_size = 0.01;
bool clear = true;
bool force_sub_emit = false;
- Transform emission_transform;
+ Transform3D emission_transform;
Vector<uint8_t> emission_buffer_data;
@@ -773,7 +798,7 @@ private:
Dependency dependency;
- float trail_length = 1.0;
+ double trail_length = 1.0;
bool trails_enabled = false;
LocalVector<ParticlesFrameParams> frame_history;
LocalVector<ParticlesFrameParams> trail_params;
@@ -782,7 +807,7 @@ private:
}
};
- void _particles_process(Particles *p_particles, float p_delta);
+ void _particles_process(Particles *p_particles, double p_delta);
void _particles_allocate_emission_buffer(Particles *particles);
void _particles_free_data(Particles *particles);
void _particles_update_buffers(Particles *particles);
@@ -820,6 +845,11 @@ private:
float align_up[3];
uint32_t align_mode;
+
+ uint32_t order_by_lifetime;
+ uint32_t lifetime_split;
+ uint32_t lifetime_reverse;
+ uint32_t pad;
};
enum {
@@ -843,6 +873,7 @@ private:
struct ParticlesShaderData : public ShaderData {
bool valid;
RID version;
+ bool uses_collision = false;
//PipelineCacheRD pipelines[SKY_VERSION_MAX];
Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
@@ -853,14 +884,14 @@ private:
String path;
String code;
- Map<StringName, RID> default_texture_params;
+ Map<StringName, Map<int, RID>> default_texture_params;
RID pipeline;
bool uses_time;
virtual void set_code(const String &p_Code);
- virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
@@ -879,17 +910,14 @@ private:
}
struct ParticlesMaterialData : public MaterialData {
- uint64_t last_frame;
- ParticlesShaderData *shader_data;
- RID uniform_buffer;
+ uint64_t last_frame = 0;
+ ParticlesShaderData *shader_data = nullptr;
RID uniform_set;
- Vector<RID> texture_cache;
- Vector<uint8_t> ubo_data;
- bool uniform_set_updated;
+ bool uniform_set_updated = false;
virtual void set_render_priority(int p_priority) {}
virtual void set_next_pass(RID p_pass) {}
- virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual ~ParticlesMaterialData();
};
@@ -926,12 +954,36 @@ private:
struct ParticlesCollisionInstance {
RID collision;
- Transform transform;
+ Transform3D transform;
bool active = false;
};
mutable RID_Owner<ParticlesCollisionInstance> particles_collision_instance_owner;
+ /* FOG VOLUMES */
+
+ struct FogVolume {
+ RID material;
+ Vector3 extents = Vector3(1, 1, 1);
+
+ RS::FogVolumeShape shape = RS::FOG_VOLUME_SHAPE_BOX;
+
+ Dependency dependency;
+ };
+
+ mutable RID_Owner<FogVolume, true> fog_volume_owner;
+
+ /* visibility_notifier */
+
+ struct VisibilityNotifier {
+ AABB aabb;
+ Callable enter_callback;
+ Callable exit_callback;
+ Dependency dependency;
+ };
+
+ mutable RID_Owner<VisibilityNotifier> visibility_notifier_owner;
+
/* Skeleton */
struct Skeleton {
@@ -976,7 +1028,6 @@ private:
uint32_t cull_mask = 0xFFFFFFFF;
RS::LightOmniShadowMode omni_shadow_mode = RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
RS::LightDirectionalShadowMode directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
- RS::LightDirectionalShadowDepthRangeMode directional_range_mode = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE;
bool directional_blend_splits = false;
bool directional_sky_only = false;
uint64_t version = 0;
@@ -1030,9 +1081,9 @@ private:
mutable RID_Owner<Decal, true> decal_owner;
- /* GI PROBE */
+ /* VOXEL GI */
- struct GIProbe {
+ struct VoxelGI {
RID octree_buffer;
RID data_buffer;
RID sdf_texture;
@@ -1044,14 +1095,12 @@ private:
int cell_count = 0;
- Transform to_cell_xform;
+ Transform3D to_cell_xform;
AABB bounds;
Vector3i octree_size;
float dynamic_range = 4.0;
float energy = 1.0;
- float ao = 0.0;
- float ao_size = 0.5;
float bias = 1.4;
float normal_bias = 0.0;
float propagation = 0.7;
@@ -1066,12 +1115,7 @@ private:
Dependency dependency;
};
- GiprobeSdfShaderRD giprobe_sdf_shader;
- RID giprobe_sdf_shader_version;
- RID giprobe_sdf_shader_version_shader;
- RID giprobe_sdf_shader_pipeline;
-
- mutable RID_Owner<GIProbe, true> gi_probe_owner;
+ mutable RID_Owner<VoxelGI, true> voxel_gi_owner;
/* REFLECTION PROBE */
@@ -1110,6 +1154,7 @@ private:
struct RenderTarget {
Size2i size;
+ uint32_t view_count;
RID framebuffer;
RID color;
@@ -1120,6 +1165,8 @@ private:
bool flags[RENDER_TARGET_FLAG_MAX];
+ bool sdf_enabled = false;
+
RID backbuffer; //used for effects
RID backbuffer_fb;
RID backbuffer_mipmap0;
@@ -1253,7 +1300,7 @@ private:
void _update_global_variables();
/* EFFECTS */
- EffectsRD effects;
+ EffectsRD *effects = nullptr;
public:
virtual bool can_create_resources_async() const;
@@ -1269,7 +1316,6 @@ public:
virtual void _texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate);
- virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0); //mostly used for video and streaming
virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data);
virtual void texture_proxy_update(RID p_texture, RID p_proxy_to);
@@ -1320,7 +1366,7 @@ public:
if (p_texture.is_null()) {
return RID();
}
- Texture *tex = texture_owner.getornull(p_texture);
+ Texture *tex = texture_owner.get_or_null(p_texture);
if (!tex) {
return RID();
@@ -1332,7 +1378,7 @@ public:
if (p_texture.is_null()) {
return Size2i();
}
- Texture *tex = texture_owner.getornull(p_texture);
+ Texture *tex = texture_owner.get_or_null(p_texture);
if (!tex) {
return Size2i();
@@ -1346,6 +1392,13 @@ public:
_FORCE_INLINE_ RID sampler_rd_get_default(RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat) {
return default_rd_samplers[p_filter][p_repeat];
}
+ _FORCE_INLINE_ RID sampler_rd_get_custom(RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat) {
+ return custom_rd_samplers[p_filter][p_repeat];
+ }
+
+ void sampler_rd_configure_custom(float mipmap_bias);
+
+ void sampler_rd_set_default(float p_mipmap_bias);
/* CANVAS TEXTURE API */
@@ -1369,8 +1422,8 @@ public:
String shader_get_code(RID p_shader) const;
void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const;
- void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture);
- RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const;
+ void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index);
+ RID shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const;
Variant shader_get_param_default(RID p_shader, const StringName &p_param) const;
void shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function);
@@ -1400,12 +1453,12 @@ public:
void material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function);
_FORCE_INLINE_ uint32_t material_get_shader_id(RID p_material) {
- Material *material = material_owner.getornull(p_material);
+ Material *material = material_owner.get_or_null(p_material);
return material->shader_id;
}
_FORCE_INLINE_ MaterialData *material_get_data(RID p_material, ShaderType p_shader_type) {
- Material *material = material_owner.getornull(p_material);
+ Material *material = material_owner.get_or_null(p_material);
if (!material || material->shader_type != p_shader_type) {
return nullptr;
} else {
@@ -1428,7 +1481,9 @@ public:
virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode);
virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const;
- virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data);
+ virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data);
+ virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data);
+ virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data);
virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material);
virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const;
@@ -1456,7 +1511,7 @@ public:
virtual void update_mesh_instances();
_FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND_V(!mesh, nullptr);
r_surface_count = mesh->surface_count;
if (r_surface_count == 0) {
@@ -1473,7 +1528,7 @@ public:
}
_FORCE_INLINE_ void *mesh_get_surface(RID p_mesh, uint32_t p_surface_index) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND_V(!mesh, nullptr);
ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, nullptr);
@@ -1481,7 +1536,7 @@ public:
}
_FORCE_INLINE_ RID mesh_get_shadow_mesh(RID p_mesh) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND_V(!mesh, RID());
return mesh->shadow_mesh;
@@ -1497,10 +1552,18 @@ public:
return s->lod_count > 0;
}
- _FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_lod_threshold) const {
+ _FORCE_INLINE_ uint32_t mesh_surface_get_vertices_drawn_count(void *p_surface) const {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+ return s->index_count ? s->index_count : s->vertex_count;
+ }
+
+ _FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_lod_threshold, uint32_t *r_index_count = nullptr) const {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
int32_t current_lod = -1;
+ if (r_index_count) {
+ *r_index_count = s->index_count;
+ }
for (uint32_t i = 0; i < s->lod_count; i++) {
float screen_size = s->lods[i].edge_length * p_model_scale / p_distance_threshold;
if (screen_size > p_lod_threshold) {
@@ -1511,6 +1574,9 @@ public:
if (current_lod == -1) {
return 0;
} else {
+ if (r_index_count) {
+ *r_index_count = s->lods[current_lod].index_count;
+ }
return current_lod + 1;
}
}
@@ -1556,7 +1622,7 @@ public:
}
_FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
- MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance);
+ MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
ERR_FAIL_COND(!mi);
Mesh *mesh = mi->mesh;
ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count);
@@ -1597,7 +1663,7 @@ public:
}
_FORCE_INLINE_ uint32_t mesh_surface_get_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
Mesh::Surface *s = mesh->surfaces[p_surface_index];
if (s->render_pass != p_render_pass) {
@@ -1610,7 +1676,7 @@ public:
}
_FORCE_INLINE_ uint32_t mesh_surface_get_multimesh_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
Mesh::Surface *s = mesh->surfaces[p_surface_index];
if (s->multimesh_render_pass != p_render_pass) {
@@ -1623,7 +1689,7 @@ public:
}
_FORCE_INLINE_ uint32_t mesh_surface_get_particles_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
Mesh::Surface *s = mesh->surfaces[p_surface_index];
if (s->particles_render_pass != p_render_pass) {
@@ -1644,14 +1710,14 @@ public:
int multimesh_get_instance_count(RID p_multimesh) const;
void multimesh_set_mesh(RID p_multimesh, RID p_mesh);
- void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform);
+ void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform);
void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform);
void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color);
void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color);
RID multimesh_get_mesh(RID p_multimesh) const;
- Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const;
+ Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const;
Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const;
Color multimesh_instance_get_color(RID p_multimesh, int p_index) const;
Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const;
@@ -1665,22 +1731,22 @@ public:
AABB multimesh_get_aabb(RID p_multimesh) const;
_FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
return multimesh->xform_format;
}
_FORCE_INLINE_ bool multimesh_uses_colors(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
return multimesh->uses_colors;
}
_FORCE_INLINE_ bool multimesh_uses_custom_data(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
return multimesh->uses_custom_data;
}
_FORCE_INLINE_ uint32_t multimesh_get_instances_to_draw(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
if (multimesh->visible_instances >= 0) {
return multimesh->visible_instances;
}
@@ -1688,7 +1754,7 @@ public:
}
_FORCE_INLINE_ RID multimesh_get_3d_uniform_set(RID p_multimesh, RID p_shader, uint32_t p_set) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
if (!multimesh->uniform_set_3d.is_valid()) {
Vector<RD::Uniform> uniforms;
RD::Uniform u;
@@ -1703,7 +1769,7 @@ public:
}
_FORCE_INLINE_ RID multimesh_get_2d_uniform_set(RID p_multimesh, RID p_shader, uint32_t p_set) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
if (!multimesh->uniform_set_2d.is_valid()) {
Vector<RD::Uniform> uniforms;
RD::Uniform u;
@@ -1717,24 +1783,6 @@ public:
return multimesh->uniform_set_2d;
}
- /* IMMEDIATE API */
-
- RID immediate_allocate() { return RID(); }
- void immediate_initialize(RID p_immediate) {}
-
- virtual void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) {}
- virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) {}
- virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal) {}
- virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) {}
- virtual void immediate_color(RID p_immediate, const Color &p_color) {}
- virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) {}
- virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) {}
- virtual void immediate_end(RID p_immediate) {}
- virtual void immediate_clear(RID p_immediate) {}
- virtual void immediate_set_material(RID p_immediate, RID p_material) {}
- virtual RID immediate_get_material(RID p_immediate) const { return RID(); }
- virtual AABB immediate_get_aabb(RID p_immediate) const { return AABB(); }
-
/* SKELETON API */
RID skeleton_allocate();
@@ -1742,19 +1790,19 @@ public:
void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false);
void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform);
- void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform);
+ void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform3D &p_world_transform);
int skeleton_get_bone_count(RID p_skeleton) const;
- void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform);
- Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const;
+ void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform);
+ Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const;
void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform);
Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const;
_FORCE_INLINE_ bool skeleton_is_valid(RID p_skeleton) {
- return skeleton_owner.getornull(p_skeleton) != nullptr;
+ return skeleton_owner.get_or_null(p_skeleton) != nullptr;
}
_FORCE_INLINE_ RID skeleton_get_3d_uniform_set(RID p_skeleton, RID p_shader, uint32_t p_set) const {
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
ERR_FAIL_COND_V(!skeleton, RID());
ERR_FAIL_COND_V(skeleton->size == 0, RID());
if (skeleton->use_2d) {
@@ -1803,14 +1851,12 @@ public:
bool light_directional_get_blend_splits(RID p_light) const;
void light_directional_set_sky_only(RID p_light, bool p_sky_only);
bool light_directional_is_sky_only(RID p_light) const;
- void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode);
- RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const;
RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light);
RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light);
_FORCE_INLINE_ RS::LightType light_get_type(RID p_light) const {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
return light->type;
@@ -1818,63 +1864,70 @@ public:
AABB light_get_aabb(RID p_light) const;
_FORCE_INLINE_ float light_get_param(RID p_light, RS::LightParam p_param) {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, 0);
return light->param[p_param];
}
_FORCE_INLINE_ RID light_get_projector(RID p_light) {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, RID());
return light->projector;
}
_FORCE_INLINE_ Color light_get_color(RID p_light) {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, Color());
return light->color;
}
_FORCE_INLINE_ Color light_get_shadow_color(RID p_light) {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, Color());
return light->shadow_color;
}
_FORCE_INLINE_ uint32_t light_get_cull_mask(RID p_light) {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, 0);
return light->cull_mask;
}
_FORCE_INLINE_ bool light_has_shadow(RID p_light) const {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
return light->shadow;
}
+ _FORCE_INLINE_ bool light_has_projector(RID p_light) const {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+
+ return texture_owner.owns(light->projector);
+ }
+
_FORCE_INLINE_ bool light_is_negative(RID p_light) const {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
return light->negative;
}
_FORCE_INLINE_ float light_get_transmittance_bias(RID p_light) const {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, 0.0);
return light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS];
}
_FORCE_INLINE_ float light_get_shadow_volumetric_fog_fade(RID p_light) const {
- const Light *light = light_owner.getornull(p_light);
+ const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, 0.0);
return light->param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE];
@@ -1941,120 +1994,114 @@ public:
virtual void decal_set_normal_fade(RID p_decal, float p_fade);
_FORCE_INLINE_ Vector3 decal_get_extents(RID p_decal) {
- const Decal *decal = decal_owner.getornull(p_decal);
+ const Decal *decal = decal_owner.get_or_null(p_decal);
return decal->extents;
}
_FORCE_INLINE_ RID decal_get_texture(RID p_decal, RS::DecalTexture p_texture) {
- const Decal *decal = decal_owner.getornull(p_decal);
+ const Decal *decal = decal_owner.get_or_null(p_decal);
return decal->textures[p_texture];
}
_FORCE_INLINE_ Color decal_get_modulate(RID p_decal) {
- const Decal *decal = decal_owner.getornull(p_decal);
+ const Decal *decal = decal_owner.get_or_null(p_decal);
return decal->modulate;
}
_FORCE_INLINE_ float decal_get_emission_energy(RID p_decal) {
- const Decal *decal = decal_owner.getornull(p_decal);
+ const Decal *decal = decal_owner.get_or_null(p_decal);
return decal->emission_energy;
}
_FORCE_INLINE_ float decal_get_albedo_mix(RID p_decal) {
- const Decal *decal = decal_owner.getornull(p_decal);
+ const Decal *decal = decal_owner.get_or_null(p_decal);
return decal->albedo_mix;
}
_FORCE_INLINE_ uint32_t decal_get_cull_mask(RID p_decal) {
- const Decal *decal = decal_owner.getornull(p_decal);
+ const Decal *decal = decal_owner.get_or_null(p_decal);
return decal->cull_mask;
}
_FORCE_INLINE_ float decal_get_upper_fade(RID p_decal) {
- const Decal *decal = decal_owner.getornull(p_decal);
+ const Decal *decal = decal_owner.get_or_null(p_decal);
return decal->upper_fade;
}
_FORCE_INLINE_ float decal_get_lower_fade(RID p_decal) {
- const Decal *decal = decal_owner.getornull(p_decal);
+ const Decal *decal = decal_owner.get_or_null(p_decal);
return decal->lower_fade;
}
_FORCE_INLINE_ float decal_get_normal_fade(RID p_decal) {
- const Decal *decal = decal_owner.getornull(p_decal);
+ const Decal *decal = decal_owner.get_or_null(p_decal);
return decal->normal_fade;
}
_FORCE_INLINE_ bool decal_is_distance_fade_enabled(RID p_decal) {
- const Decal *decal = decal_owner.getornull(p_decal);
+ const Decal *decal = decal_owner.get_or_null(p_decal);
return decal->distance_fade;
}
_FORCE_INLINE_ float decal_get_distance_fade_begin(RID p_decal) {
- const Decal *decal = decal_owner.getornull(p_decal);
+ const Decal *decal = decal_owner.get_or_null(p_decal);
return decal->distance_fade_begin;
}
_FORCE_INLINE_ float decal_get_distance_fade_length(RID p_decal) {
- const Decal *decal = decal_owner.getornull(p_decal);
+ const Decal *decal = decal_owner.get_or_null(p_decal);
return decal->distance_fade_length;
}
virtual AABB decal_get_aabb(RID p_decal) const;
- /* GI PROBE API */
-
- RID gi_probe_allocate();
- void gi_probe_initialize(RID p_gi_probe);
+ /* VOXEL GI API */
- void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts);
+ RID voxel_gi_allocate();
+ void voxel_gi_initialize(RID p_voxel_gi);
- AABB gi_probe_get_bounds(RID p_gi_probe) const;
- Vector3i gi_probe_get_octree_size(RID p_gi_probe) const;
- Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const;
- Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const;
- Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const;
+ void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts);
- Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const;
- Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const;
+ AABB voxel_gi_get_bounds(RID p_voxel_gi) const;
+ Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const;
+ Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const;
+ Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const;
+ Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const;
- void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range);
- float gi_probe_get_dynamic_range(RID p_gi_probe) const;
+ Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const;
+ Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const;
- void gi_probe_set_propagation(RID p_gi_probe, float p_range);
- float gi_probe_get_propagation(RID p_gi_probe) const;
+ void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range);
+ float voxel_gi_get_dynamic_range(RID p_voxel_gi) const;
- void gi_probe_set_energy(RID p_gi_probe, float p_energy);
- float gi_probe_get_energy(RID p_gi_probe) const;
+ void voxel_gi_set_propagation(RID p_voxel_gi, float p_range);
+ float voxel_gi_get_propagation(RID p_voxel_gi) const;
- void gi_probe_set_ao(RID p_gi_probe, float p_ao);
- float gi_probe_get_ao(RID p_gi_probe) const;
+ void voxel_gi_set_energy(RID p_voxel_gi, float p_energy);
+ float voxel_gi_get_energy(RID p_voxel_gi) const;
- void gi_probe_set_ao_size(RID p_gi_probe, float p_strength);
- float gi_probe_get_ao_size(RID p_gi_probe) const;
+ void voxel_gi_set_bias(RID p_voxel_gi, float p_bias);
+ float voxel_gi_get_bias(RID p_voxel_gi) const;
- void gi_probe_set_bias(RID p_gi_probe, float p_bias);
- float gi_probe_get_bias(RID p_gi_probe) const;
+ void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range);
+ float voxel_gi_get_normal_bias(RID p_voxel_gi) const;
- void gi_probe_set_normal_bias(RID p_gi_probe, float p_range);
- float gi_probe_get_normal_bias(RID p_gi_probe) const;
+ void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable);
+ bool voxel_gi_is_interior(RID p_voxel_gi) const;
- void gi_probe_set_interior(RID p_gi_probe, bool p_enable);
- bool gi_probe_is_interior(RID p_gi_probe) const;
+ void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable);
+ bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const;
- void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable);
- bool gi_probe_is_using_two_bounces(RID p_gi_probe) const;
+ void voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength);
+ float voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const;
- void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength);
- float gi_probe_get_anisotropy_strength(RID p_gi_probe) const;
+ uint32_t voxel_gi_get_version(RID p_probe);
+ uint32_t voxel_gi_get_data_version(RID p_probe);
- uint32_t gi_probe_get_version(RID p_probe);
- uint32_t gi_probe_get_data_version(RID p_probe);
+ RID voxel_gi_get_octree_buffer(RID p_voxel_gi) const;
+ RID voxel_gi_get_data_buffer(RID p_voxel_gi) const;
- RID gi_probe_get_octree_buffer(RID p_gi_probe) const;
- RID gi_probe_get_data_buffer(RID p_gi_probe) const;
-
- RID gi_probe_get_sdf_texture(RID p_gi_probe);
+ RID voxel_gi_get_sdf_texture(RID p_voxel_gi);
/* LIGHTMAP CAPTURE */
@@ -2077,18 +2124,18 @@ public:
return lightmap_probe_capture_update_speed;
}
_FORCE_INLINE_ RID lightmap_get_texture(RID p_lightmap) const {
- const Lightmap *lm = lightmap_owner.getornull(p_lightmap);
+ const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND_V(!lm, RID());
return lm->light_texture;
}
_FORCE_INLINE_ int32_t lightmap_get_array_index(RID p_lightmap) const {
ERR_FAIL_COND_V(!using_lightmap_array, -1); //only for arrays
- const Lightmap *lm = lightmap_owner.getornull(p_lightmap);
+ const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
return lm->array_index;
}
_FORCE_INLINE_ bool lightmap_uses_spherical_harmonics(RID p_lightmap) const {
ERR_FAIL_COND_V(!using_lightmap_array, false); //only for arrays
- const Lightmap *lm = lightmap_owner.getornull(p_lightmap);
+ const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
return lm->uses_spherical_harmonics;
}
_FORCE_INLINE_ uint64_t lightmap_array_get_version() const {
@@ -2114,26 +2161,26 @@ public:
void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode);
void particles_set_emitting(RID p_particles, bool p_emitting);
void particles_set_amount(RID p_particles, int p_amount);
- void particles_set_lifetime(RID p_particles, float p_lifetime);
+ void particles_set_lifetime(RID p_particles, double p_lifetime);
void particles_set_one_shot(RID p_particles, bool p_one_shot);
- void particles_set_pre_process_time(RID p_particles, float p_time);
- void particles_set_explosiveness_ratio(RID p_particles, float p_ratio);
- void particles_set_randomness_ratio(RID p_particles, float p_ratio);
+ void particles_set_pre_process_time(RID p_particles, double p_time);
+ void particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio);
+ void particles_set_randomness_ratio(RID p_particles, real_t p_ratio);
void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb);
- void particles_set_speed_scale(RID p_particles, float p_scale);
+ void particles_set_speed_scale(RID p_particles, double p_scale);
void particles_set_use_local_coordinates(RID p_particles, bool p_enable);
void particles_set_process_material(RID p_particles, RID p_material);
void particles_set_fixed_fps(RID p_particles, int p_fps);
void particles_set_interpolate(RID p_particles, bool p_enable);
void particles_set_fractional_delta(RID p_particles, bool p_enable);
- void particles_set_collision_base_size(RID p_particles, float p_size);
+ void particles_set_collision_base_size(RID p_particles, real_t p_size);
void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align);
- void particles_set_trails(RID p_particles, bool p_enable, float p_length);
- void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses);
+ void particles_set_trails(RID p_particles, bool p_enable, double p_length);
+ void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses);
void particles_restart(RID p_particles);
- void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags);
+ void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags);
void particles_set_subemitter(RID p_particles, RID p_subemitter_particles);
@@ -2146,7 +2193,7 @@ public:
AABB particles_get_current_aabb(RID p_particles);
AABB particles_get_aabb(RID p_particles) const;
- void particles_set_emission_transform(RID p_particles, const Transform &p_transform);
+ void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform);
bool particles_get_emitting(RID p_particles);
int particles_get_draw_passes(RID p_particles) const;
@@ -2157,13 +2204,13 @@ public:
virtual bool particles_is_inactive(RID p_particles) const;
_FORCE_INLINE_ RS::ParticlesMode particles_get_mode(RID p_particles) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, RS::PARTICLES_MODE_2D);
return particles->mode;
}
_FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles, uint32_t &r_trail_divisor) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, 0);
if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
@@ -2175,15 +2222,22 @@ public:
return particles->amount * r_trail_divisor;
}
+ _FORCE_INLINE_ bool particles_has_collision(RID p_particles) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND_V(!particles, 0);
+
+ return particles->has_collision_cache;
+ }
+
_FORCE_INLINE_ uint32_t particles_is_using_local_coords(RID p_particles) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, false);
return particles->use_local_coords;
}
_FORCE_INLINE_ RID particles_get_instance_buffer_uniform_set(RID p_particles, RID p_shader, uint32_t p_set) {
- Particles *particles = particles_owner.getornull(p_particles);
+ Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, RID());
if (particles->particles_transforms_buffer_uniform_set.is_null()) {
_particles_update_buffers(particles);
@@ -2206,6 +2260,7 @@ public:
virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance);
virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance);
+ virtual void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture);
/* PARTICLES COLLISION */
@@ -2214,11 +2269,11 @@ public:
virtual void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type);
virtual void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask);
- virtual void particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius); //for spheres
+ virtual void particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius); //for spheres
virtual void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents); //for non-spheres
- virtual void particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength);
- virtual void particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality);
- virtual void particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve);
+ virtual void particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength);
+ virtual void particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality);
+ virtual void particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve);
virtual void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture); //for SDF and vector field, heightfield is dynamic
virtual void particles_collision_height_field_update(RID p_particles_collision); //for SDF and vector field
virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution); //for SDF and vector field
@@ -2227,9 +2282,32 @@ public:
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const;
RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const;
+ /* FOG VOLUMES */
+
+ virtual RID fog_volume_allocate();
+ virtual void fog_volume_initialize(RID p_rid);
+
+ virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape);
+ virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents);
+ virtual void fog_volume_set_material(RID p_fog_volume, RID p_material);
+ virtual RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const;
+ virtual RID fog_volume_get_material(RID p_fog_volume) const;
+ virtual AABB fog_volume_get_aabb(RID p_fog_volume) const;
+ virtual Vector3 fog_volume_get_extents(RID p_fog_volume) const;
+
+ /* VISIBILITY NOTIFIER */
+
+ virtual RID visibility_notifier_allocate();
+ virtual void visibility_notifier_initialize(RID p_notifier);
+ virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb);
+ virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable);
+
+ virtual AABB visibility_notifier_get_aabb(RID p_notifier) const;
+ virtual void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred);
+
//used from 2D and 3D
virtual RID particles_collision_instance_create(RID p_collision);
- virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform);
+ virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform);
virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active);
/* GLOBAL VARIABLES API */
@@ -2257,7 +2335,7 @@ public:
RID render_target_create();
void render_target_set_position(RID p_render_target, int p_x, int p_y);
- void render_target_set_size(RID p_render_target, int p_width, int p_height);
+ void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count);
RID render_target_get_texture(RID p_render_target);
void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id);
void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);
@@ -2280,6 +2358,8 @@ public:
RID render_target_get_sdf_framebuffer(RID p_render_target);
void render_target_sdf_process(RID p_render_target);
virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const;
+ void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled);
+ bool render_target_is_sdf_enabled(RID p_render_target) const;
Size2 render_target_get_size(RID p_render_target);
RID render_target_get_rd_framebuffer(RID p_render_target);
@@ -2303,13 +2383,16 @@ public:
void set_debug_generate_wireframes(bool p_generate) {}
- void render_info_begin_capture() {}
- void render_info_end_capture() {}
- int get_captured_render_info(RS::RenderInfo p_info) { return 0; }
+ //keep cached since it can be called form any thread
+ uint64_t texture_mem_cache = 0;
+ uint64_t buffer_mem_cache = 0;
+ uint64_t total_mem_cache = 0;
+
+ virtual void update_memory_info();
+ virtual uint64_t get_rendering_info(RS::RenderingInfo p_info);
- uint64_t get_render_info(RS::RenderInfo p_info) { return 0; }
- String get_video_adapter_name() const { return String(); }
- String get_video_adapter_vendor() const { return String(); }
+ String get_video_adapter_name() const;
+ String get_video_adapter_vendor() const;
virtual void capture_timestamps_begin();
virtual void capture_timestamp(const String &p_name);
@@ -2323,6 +2406,7 @@ public:
static RendererStorageRD *base_singleton;
+ void init_effects(bool p_prefer_raster_effects);
EffectsRD *get_effects();
RendererStorageRD();
diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp
index 24ac85bb35..77d3a2e766 100644
--- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp
@@ -91,7 +91,7 @@ static int _get_datatype_size(SL::DataType p_type) {
case SL::TYPE_VEC4:
return 16;
case SL::TYPE_MAT2:
- return 32; //4 * 4 + 4 * 4
+ return 32; // 4 * 4 + 4 * 4
case SL::TYPE_MAT3:
return 48; // 4 * 4 + 4 * 4 + 4 * 4
case SL::TYPE_MAT4:
@@ -213,7 +213,7 @@ static String _interpstr(SL::DataInterpolation p_interp) {
return "";
}
-static String _prestr(SL::DataPrecision p_pres) {
+static String _prestr(SL::DataPrecision p_pres, bool p_force_highp = false) {
switch (p_pres) {
case SL::PRECISION_LOWP:
return "lowp ";
@@ -222,7 +222,14 @@ static String _prestr(SL::DataPrecision p_pres) {
case SL::PRECISION_HIGHP:
return "highp ";
case SL::PRECISION_DEFAULT:
- return "";
+ return p_force_highp ? "highp " : "";
+ }
+ return "";
+}
+
+static String _constr(bool p_is_const) {
+ if (p_is_const) {
+ return "const ";
}
return "";
}
@@ -369,17 +376,24 @@ void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const S
ERR_FAIL_COND(fidx == -1);
+ Vector<StringName> uses_functions;
+
for (Set<StringName>::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) {
- if (added.has(E->get())) {
+ uses_functions.push_back(E->get());
+ }
+ uses_functions.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced
+
+ for (int k = 0; k < uses_functions.size(); k++) {
+ if (added.has(uses_functions[k])) {
continue; //was added already
}
- _dump_function_deps(p_node, E->get(), p_func_code, r_to_add, added);
+ _dump_function_deps(p_node, uses_functions[k], p_func_code, r_to_add, added);
SL::FunctionNode *fnode = nullptr;
for (int i = 0; i < p_node->functions.size(); i++) {
- if (p_node->functions[i].name == E->get()) {
+ if (p_node->functions[i].name == uses_functions[k]) {
fnode = p_node->functions[i].function;
break;
}
@@ -391,29 +405,43 @@ void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const S
String header;
if (fnode->return_type == SL::TYPE_STRUCT) {
- header = _mkid(fnode->return_struct_name) + " " + _mkid(fnode->name) + "(";
+ header = _mkid(fnode->return_struct_name);
} else {
- header = _typestr(fnode->return_type) + " " + _mkid(fnode->name) + "(";
+ header = _typestr(fnode->return_type);
+ }
+
+ if (fnode->return_array_size > 0) {
+ header += "[";
+ header += itos(fnode->return_array_size);
+ header += "]";
}
+
+ header += " ";
+ header += _mkid(fnode->name);
+ header += "(";
+
for (int i = 0; i < fnode->arguments.size(); i++) {
if (i > 0) {
header += ", ";
}
- if (fnode->arguments[i].is_const) {
- header += "const ";
- }
+ header += _constr(fnode->arguments[i].is_const);
if (fnode->arguments[i].type == SL::TYPE_STRUCT) {
header += _qualstr(fnode->arguments[i].qualifier) + _mkid(fnode->arguments[i].type_str) + " " + _mkid(fnode->arguments[i].name);
} else {
header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name);
}
+ if (fnode->arguments[i].array_size > 0) {
+ header += "[";
+ header += itos(fnode->arguments[i].array_size);
+ header += "]";
+ }
}
header += ")\n";
r_to_add += header;
- r_to_add += p_func_code[E->get()];
+ r_to_add += p_func_code[uses_functions[k]];
- added.insert(E->get());
+ added.insert(uses_functions[k]);
}
}
@@ -543,12 +571,12 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
int max_texture_uniforms = 0;
int max_uniforms = 0;
- for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
- if (SL::is_sampler_type(E->get().type)) {
+ for (const KeyValue<StringName, SL::ShaderNode::Uniform> &E : pnode->uniforms) {
+ if (SL::is_sampler_type(E.value.type)) {
max_texture_uniforms++;
} else {
- if (E->get().scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue; //instances are indexed directly, dont need index uniforms
+ if (E.value.scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue; // Instances are indexed directly, don't need index uniforms.
}
max_uniforms++;
@@ -565,63 +593,91 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
uniform_defines.resize(max_uniforms);
bool uses_uniforms = false;
- for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
+ Vector<StringName> uniform_names;
+
+ for (const KeyValue<StringName, SL::ShaderNode::Uniform> &E : pnode->uniforms) {
+ uniform_names.push_back(E.key);
+ }
+
+ uniform_names.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced
+
+ for (int k = 0; k < uniform_names.size(); k++) {
+ StringName uniform_name = uniform_names[k];
+ const SL::ShaderNode::Uniform &uniform = pnode->uniforms[uniform_name];
+
String ucode;
- if (E->get().scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ if (uniform.scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
//insert, but don't generate any code.
- p_actions.uniforms->insert(E->key(), E->get());
- continue; //instances are indexed directly, dont need index uniforms
+ p_actions.uniforms->insert(uniform_name, uniform);
+ continue; // Instances are indexed directly, don't need index uniforms.
}
- if (SL::is_sampler_type(E->get().type)) {
- ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + E->get().texture_order) + ") uniform ";
+ if (SL::is_sampler_type(uniform.type)) {
+ ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_binding) + ") uniform ";
}
- bool is_buffer_global = !SL::is_sampler_type(E->get().type) && E->get().scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL;
+ bool is_buffer_global = !SL::is_sampler_type(uniform.type) && uniform.scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL;
if (is_buffer_global) {
//this is an integer to index the global table
ucode += _typestr(ShaderLanguage::TYPE_UINT);
} else {
- ucode += _prestr(E->get().precision);
- ucode += _typestr(E->get().type);
+ ucode += _prestr(uniform.precision, ShaderLanguage::is_float_type(uniform.type));
+ ucode += _typestr(uniform.type);
}
- ucode += " " + _mkid(E->key());
+ ucode += " " + _mkid(uniform_name);
+ if (uniform.array_size > 0) {
+ ucode += "[";
+ ucode += itos(uniform.array_size);
+ ucode += "]";
+ }
ucode += ";\n";
- if (SL::is_sampler_type(E->get().type)) {
+ if (SL::is_sampler_type(uniform.type)) {
for (int j = 0; j < STAGE_MAX; j++) {
r_gen_code.stage_globals[j] += ucode;
}
GeneratedCode::Texture texture;
- texture.name = E->key();
- texture.hint = E->get().hint;
- texture.type = E->get().type;
- texture.filter = E->get().filter;
- texture.repeat = E->get().repeat;
- texture.global = E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL;
+ texture.name = uniform_name;
+ texture.hint = uniform.hint;
+ texture.type = uniform.type;
+ texture.filter = uniform.filter;
+ texture.repeat = uniform.repeat;
+ texture.global = uniform.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL;
+ texture.array_size = uniform.array_size;
if (texture.global) {
r_gen_code.uses_global_textures = true;
}
- r_gen_code.texture_uniforms.write[E->get().texture_order] = texture;
+ r_gen_code.texture_uniforms.write[uniform.texture_order] = texture;
} else {
if (!uses_uniforms) {
uses_uniforms = true;
}
- uniform_defines.write[E->get().order] = ucode;
+ uniform_defines.write[uniform.order] = ucode;
if (is_buffer_global) {
//globals are indices into the global table
- uniform_sizes.write[E->get().order] = _get_datatype_size(ShaderLanguage::TYPE_UINT);
- uniform_alignments.write[E->get().order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT);
+ uniform_sizes.write[uniform.order] = _get_datatype_size(ShaderLanguage::TYPE_UINT);
+ uniform_alignments.write[uniform.order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT);
} else {
- uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type);
- uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type);
+ // The following code enforces a 16-byte alignment of uniform arrays.
+ if (uniform.array_size > 0) {
+ int size = _get_datatype_size(uniform.type) * uniform.array_size;
+ int m = (16 * uniform.array_size);
+ if ((size % m) != 0) {
+ size += m - (size % m);
+ }
+ uniform_sizes.write[uniform.order] = size;
+ uniform_alignments.write[uniform.order] = 16;
+ } else {
+ uniform_sizes.write[uniform.order] = _get_datatype_size(uniform.type);
+ uniform_alignments.write[uniform.order] = _get_datatype_alignment(uniform.type);
+ }
}
}
- p_actions.uniforms->insert(E->key(), E->get());
+ p_actions.uniforms->insert(uniform_name, uniform);
}
for (int i = 0; i < max_uniforms; i++) {
@@ -688,21 +744,32 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
List<Pair<StringName, SL::ShaderNode::Varying>> var_frag_to_light;
- for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) {
- if (E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT || E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT) {
- var_frag_to_light.push_back(Pair<StringName, SL::ShaderNode::Varying>(E->key(), E->get()));
- fragment_varyings.insert(E->key());
+ Vector<StringName> varying_names;
+
+ for (const KeyValue<StringName, SL::ShaderNode::Varying> &E : pnode->varyings) {
+ varying_names.push_back(E.key);
+ }
+
+ varying_names.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced
+
+ for (int k = 0; k < varying_names.size(); k++) {
+ StringName varying_name = varying_names[k];
+ const SL::ShaderNode::Varying &varying = pnode->varyings[varying_name];
+
+ if (varying.stage == SL::ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT || varying.stage == SL::ShaderNode::Varying::STAGE_FRAGMENT) {
+ var_frag_to_light.push_back(Pair<StringName, SL::ShaderNode::Varying>(varying_name, varying));
+ fragment_varyings.insert(varying_name);
continue;
}
String vcode;
- String interp_mode = _interpstr(E->get().interpolation);
- vcode += _prestr(E->get().precision);
- vcode += _typestr(E->get().type);
- vcode += " " + _mkid(E->key());
- if (E->get().array_size > 0) {
+ String interp_mode = _interpstr(varying.interpolation);
+ vcode += _prestr(varying.precision, ShaderLanguage::is_float_type(varying.type));
+ vcode += _typestr(varying.type);
+ vcode += " " + _mkid(varying_name);
+ if (varying.array_size > 0) {
vcode += "[";
- vcode += itos(E->get().array_size);
+ vcode += itos(varying.array_size);
vcode += "]";
}
vcode += ";\n";
@@ -715,11 +782,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
if (var_frag_to_light.size() > 0) {
String gcode = "\n\nstruct {\n";
- for (List<Pair<StringName, SL::ShaderNode::Varying>>::Element *E = var_frag_to_light.front(); E; E = E->next()) {
- gcode += "\t" + _prestr(E->get().second.precision) + _typestr(E->get().second.type) + " " + _mkid(E->get().first);
- if (E->get().second.array_size > 0) {
+ for (const Pair<StringName, SL::ShaderNode::Varying> &E : var_frag_to_light) {
+ gcode += "\t" + _prestr(E.second.precision) + _typestr(E.second.type) + " " + _mkid(E.first);
+ if (E.second.array_size > 0) {
gcode += "[";
- gcode += itos(E->get().second.array_size);
+ gcode += itos(E.second.array_size);
gcode += "]";
}
gcode += ";\n";
@@ -731,8 +798,8 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
for (int i = 0; i < pnode->vconstants.size(); i++) {
const SL::ShaderNode::Constant &cnode = pnode->vconstants[i];
String gcode;
- gcode += "const ";
- gcode += _prestr(cnode.precision);
+ gcode += _constr(true);
+ gcode += _prestr(cnode.precision, ShaderLanguage::is_float_type(cnode.type));
if (cnode.type == SL::TYPE_STRUCT) {
gcode += _mkid(cnode.type_str);
} else {
@@ -815,9 +882,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
SL::VariableDeclarationNode *vdnode = (SL::VariableDeclarationNode *)p_node;
String declaration;
- if (vdnode->is_const) {
- declaration += "const ";
- }
+ declaration += _constr(vdnode->is_const);
if (vdnode->datatype == SL::TYPE_STRUCT) {
declaration += _mkid(vdnode->struct_name);
} else {
@@ -842,7 +907,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
SL::VariableNode *vnode = (SL::VariableNode *)p_node;
bool use_fragment_varying = false;
- if (!(p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX)) {
+ if (!vnode->is_local && !(p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX)) {
if (p_assigning) {
if (shader->varyings.has(vnode->name)) {
use_fragment_varying = true;
@@ -937,9 +1002,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
case SL::Node::TYPE_ARRAY_DECLARATION: {
SL::ArrayDeclarationNode *adnode = (SL::ArrayDeclarationNode *)p_node;
String declaration;
- if (adnode->is_const) {
- declaration += "const ";
- }
+ declaration += _constr(adnode->is_const);
if (adnode->datatype == SL::TYPE_STRUCT) {
declaration += _mkid(adnode->struct_name);
} else {
@@ -959,25 +1022,30 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
declaration += itos(adnode->declarations[i].size);
}
declaration += "]";
- int sz = adnode->declarations[i].initializer.size();
- if (sz > 0) {
+ if (adnode->declarations[i].single_expression) {
declaration += "=";
- if (adnode->datatype == SL::TYPE_STRUCT) {
- declaration += _mkid(adnode->struct_name);
- } else {
- declaration += _typestr(adnode->datatype);
- }
- declaration += "[";
- declaration += itos(sz);
- declaration += "]";
- declaration += "(";
- for (int j = 0; j < sz; j++) {
- declaration += _dump_node_code(adnode->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- if (j != sz - 1) {
- declaration += ", ";
+ declaration += _dump_node_code(adnode->declarations[i].initializer[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ } else {
+ int sz = adnode->declarations[i].initializer.size();
+ if (sz > 0) {
+ declaration += "=";
+ if (adnode->datatype == SL::TYPE_STRUCT) {
+ declaration += _mkid(adnode->struct_name);
+ } else {
+ declaration += _typestr(adnode->datatype);
}
+ declaration += "[";
+ declaration += itos(sz);
+ declaration += "]";
+ declaration += "(";
+ for (int j = 0; j < sz; j++) {
+ declaration += _dump_node_code(adnode->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ if (j != sz - 1) {
+ declaration += ", ";
+ }
+ }
+ declaration += ")";
}
- declaration += ")";
}
}
@@ -987,8 +1055,8 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
SL::ArrayNode *anode = (SL::ArrayNode *)p_node;
bool use_fragment_varying = false;
- if (!(p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX)) {
- if (anode->assign_expression != nullptr) {
+ if (!anode->is_local && !(p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX)) {
+ if (anode->assign_expression != nullptr && shader->varyings.has(anode->name)) {
use_fragment_varying = true;
} else {
if (p_assigning) {
@@ -1024,10 +1092,32 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
if (p_default_actions.renames.has(anode->name)) {
code = p_default_actions.renames[anode->name];
} else {
- if (use_fragment_varying) {
- code = "frag_to_light.";
+ if (shader->uniforms.has(anode->name)) {
+ //its a uniform!
+ const ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[anode->name];
+ if (u.texture_order >= 0) {
+ code = _mkid(anode->name); //texture, use as is
+ } else {
+ //a scalar or vector
+ if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) {
+ code = actions.base_uniform_string + _mkid(anode->name); //texture, use as is
+ //global variable, this means the code points to an index to the global table
+ code = _get_global_variable_from_type_and_index(p_default_actions.global_buffer_array_variable, code, u.type);
+ } else if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ //instance variable, index it as such
+ code = "(" + p_default_actions.instance_uniform_index_variable + "+" + itos(u.instance_index) + ")";
+ code = _get_global_variable_from_type_and_index(p_default_actions.global_buffer_array_variable, code, u.type);
+ } else {
+ //regular uniform, index from UBO
+ code = actions.base_uniform_string + _mkid(anode->name);
+ }
+ }
+ } else {
+ if (use_fragment_varying) {
+ code = "frag_to_light.";
+ }
+ code += _mkid(anode->name);
}
- code += _mkid(anode->name);
}
if (anode->call_expression != nullptr) {
@@ -1115,6 +1205,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
SL::VariableNode *vnode = (SL::VariableNode *)onode->arguments[0];
bool is_texture_func = false;
+ bool is_screen_texture = false;
if (onode->op == SL::OP_STRUCT) {
code += _mkid(vnode->name);
} else if (onode->op == SL::OP_CONSTRUCT) {
@@ -1142,50 +1233,73 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
code += ", ";
}
String node_code = _dump_node_code(onode->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- if (is_texture_func && i == 1 && onode->arguments[i]->type == SL::Node::TYPE_VARIABLE) {
+ if (is_texture_func && i == 1) {
//need to map from texture to sampler in order to sample
- const SL::VariableNode *varnode = static_cast<const SL::VariableNode *>(onode->arguments[i]);
+ StringName texture_uniform;
+ bool correct_texture_uniform = false;
+
+ switch (onode->arguments[i]->type) {
+ case SL::Node::TYPE_VARIABLE: {
+ const SL::VariableNode *varnode = static_cast<const SL::VariableNode *>(onode->arguments[i]);
+ texture_uniform = varnode->name;
+ correct_texture_uniform = true;
+ } break;
+ case SL::Node::TYPE_ARRAY: {
+ const SL::ArrayNode *anode = static_cast<const SL::ArrayNode *>(onode->arguments[i]);
+ texture_uniform = anode->name;
+ correct_texture_uniform = true;
+ } break;
+ default:
+ break;
+ }
- StringName texture_uniform = varnode->name;
+ if (correct_texture_uniform) {
+ is_screen_texture = (texture_uniform == "SCREEN_TEXTURE");
- String sampler_name;
+ String sampler_name;
- if (actions.custom_samplers.has(texture_uniform)) {
- sampler_name = actions.custom_samplers[texture_uniform];
- } else {
- if (shader->uniforms.has(texture_uniform)) {
- sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat);
+ if (actions.custom_samplers.has(texture_uniform)) {
+ sampler_name = actions.custom_samplers[texture_uniform];
} else {
- bool found = false;
-
- for (int j = 0; j < function->arguments.size(); j++) {
- if (function->arguments[j].name == texture_uniform) {
- if (function->arguments[j].tex_builtin_check) {
- ERR_CONTINUE(!actions.custom_samplers.has(function->arguments[j].tex_builtin));
- sampler_name = actions.custom_samplers[function->arguments[j].tex_builtin];
- found = true;
- break;
- }
- if (function->arguments[j].tex_argument_check) {
- sampler_name = _get_sampler_name(function->arguments[j].tex_argument_filter, function->arguments[j].tex_argument_repeat);
- found = true;
- break;
+ if (shader->uniforms.has(texture_uniform)) {
+ sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat);
+ } else {
+ bool found = false;
+
+ for (int j = 0; j < function->arguments.size(); j++) {
+ if (function->arguments[j].name == texture_uniform) {
+ if (function->arguments[j].tex_builtin_check) {
+ ERR_CONTINUE(!actions.custom_samplers.has(function->arguments[j].tex_builtin));
+ sampler_name = actions.custom_samplers[function->arguments[j].tex_builtin];
+ found = true;
+ break;
+ }
+ if (function->arguments[j].tex_argument_check) {
+ sampler_name = _get_sampler_name(function->arguments[j].tex_argument_filter, function->arguments[j].tex_argument_repeat);
+ found = true;
+ break;
+ }
}
}
- }
- if (!found) {
- //function was most likely unused, so use anything (compiler will remove it anyway)
- sampler_name = _get_sampler_name(ShaderLanguage::FILTER_DEFAULT, ShaderLanguage::REPEAT_DEFAULT);
+ if (!found) {
+ //function was most likely unused, so use anything (compiler will remove it anyway)
+ sampler_name = _get_sampler_name(ShaderLanguage::FILTER_DEFAULT, ShaderLanguage::REPEAT_DEFAULT);
+ }
}
}
- }
- code += ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()) + "(" + node_code + ", " + sampler_name + ")";
+ code += ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()) + "(" + node_code + ", " + sampler_name + ")";
+ } else {
+ code += node_code;
+ }
} else {
code += node_code;
}
}
code += ")";
+ if (is_screen_texture && actions.apply_luminance_multiplier) {
+ code = "(" + code + " * vec4(vec3(sc_luminance_multiplier), 1.0))";
+ }
} break;
case SL::OP_INDEX: {
code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
@@ -1280,6 +1394,9 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
} else if (mnode->assign_expression != nullptr) {
code += "=";
code += _dump_node_code(mnode->assign_expression, p_level, r_gen_code, p_actions, p_default_actions, true, false);
+ } else if (mnode->call_expression != nullptr) {
+ code += ".";
+ code += _dump_node_code(mnode->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning, false);
}
} break;
}
@@ -1298,10 +1415,16 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide
if (err != OK) {
Vector<String> shader = p_code.split("\n");
for (int i = 0; i < shader.size(); i++) {
- print_line(itos(i + 1) + " " + shader[i]);
+ if (i + 1 == parser.get_error_line()) {
+ // Mark the error line to be visible without having to look at
+ // the trace at the end.
+ print_line(vformat("E%4d-> %s", i + 1, shader[i]));
+ } else {
+ print_line(vformat("%5d | %s", i + 1, shader[i]));
+ }
}
- _err_print_error(nullptr, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), ERR_HANDLER_SHADER);
+ _err_print_error(nullptr, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), false, ERR_HANDLER_SHADER);
return err;
}
@@ -1335,14 +1458,15 @@ void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) {
ShaderLanguage::get_builtin_funcs(&func_list);
- for (List<String>::Element *E = func_list.front(); E; E = E->next()) {
- internal_functions.insert(E->get());
+ for (const String &E : func_list) {
+ internal_functions.insert(E);
}
texture_functions.insert("texture");
texture_functions.insert("textureProj");
texture_functions.insert("textureLod");
texture_functions.insert("textureProjLod");
texture_functions.insert("textureGrad");
+ texture_functions.insert("textureGather");
texture_functions.insert("textureSize");
texture_functions.insert("texelFetch");
}
@@ -1451,7 +1575,6 @@ ShaderCompilerRD::ShaderCompilerRD() {
actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
}
- actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.h b/servers/rendering/renderer_rd/shader_compiler_rd.h
index 2da127ffa3..2ab689c27c 100644
--- a/servers/rendering/renderer_rd/shader_compiler_rd.h
+++ b/servers/rendering/renderer_rd/shader_compiler_rd.h
@@ -65,6 +65,7 @@ public:
ShaderLanguage::TextureFilter filter;
ShaderLanguage::TextureRepeat repeat;
bool global;
+ int array_size;
};
Vector<Texture> texture_uniforms;
@@ -95,6 +96,7 @@ public:
String global_buffer_array_variable;
String instance_uniform_index_variable;
uint32_t base_varying_index = 0;
+ bool apply_luminance_multiplier = false;
};
private:
diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp
index f7242a2b17..2568090918 100644
--- a/servers/rendering/renderer_rd/shader_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_rd.cpp
@@ -30,8 +30,12 @@
#include "shader_rd.h"
+#include "core/io/compression.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "renderer_compositor_rd.h"
#include "servers/rendering/rendering_device.h"
+#include "thirdparty/misc/smolv.h"
void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) {
Vector<String> lines = String(p_code).split("\n");
@@ -97,6 +101,7 @@ void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) {
void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) {
name = p_name;
+
if (p_compute_code) {
_add_stage(p_compute_code, STAGE_TYPE_COMPUTE);
is_compute = true;
@@ -109,6 +114,20 @@ void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, con
_add_stage(p_fragment_code, STAGE_TYPE_FRAGMENT);
}
}
+
+ StringBuilder tohash;
+ tohash.append("[SpirvCacheKey]");
+ tohash.append(RenderingDevice::get_singleton()->shader_get_spirv_cache_key());
+ tohash.append("[BinaryCacheKey]");
+ tohash.append(RenderingDevice::get_singleton()->shader_get_binary_cache_key());
+ tohash.append("[Vertex]");
+ tohash.append(p_vertex_code ? p_vertex_code : "");
+ tohash.append("[Fragment]");
+ tohash.append(p_fragment_code ? p_fragment_code : "");
+ tohash.append("[Compute]");
+ tohash.append(p_compute_code ? p_compute_code : "");
+
+ base_sha256 = tohash.as_string().sha256_text();
}
RID ShaderRD::version_create() {
@@ -127,10 +146,15 @@ void ShaderRD::_clear_version(Version *p_version) {
//clear versions if they exist
if (p_version->variants) {
for (int i = 0; i < variant_defines.size(); i++) {
- RD::get_singleton()->free(p_version->variants[i]);
+ if (variants_enabled[i]) {
+ RD::get_singleton()->free(p_version->variants[i]);
+ }
}
memdelete_arr(p_version->variants);
+ if (p_version->variant_data) {
+ memdelete_arr(p_version->variant_data);
+ }
p_version->variants = nullptr;
}
}
@@ -150,9 +174,12 @@ void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, c
if (p_version->uniforms.size()) {
builder.append("#define MATERIAL_UNIFORMS_USED\n");
}
- for (Map<StringName, CharString>::Element *E = p_version->code_sections.front(); E; E = E->next()) {
- builder.append(String("#define ") + String(E->key()) + "_CODE_USED\n");
+ for (const KeyValue<StringName, CharString> &E : p_version->code_sections) {
+ builder.append(String("#define ") + String(E.key) + "_CODE_USED\n");
}
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ builder.append("#define MOLTENVK_USED\n");
+#endif
} break;
case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: {
builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
@@ -183,7 +210,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
return; //variant is disabled, return
}
- Vector<RD::ShaderStageData> stages;
+ Vector<RD::ShaderStageSPIRVData> stages;
String error;
String current_source;
@@ -197,8 +224,8 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
_build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_VERTEX]);
current_source = builder.as_string();
- RD::ShaderStageData stage;
- stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_VERTEX, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
+ RD::ShaderStageSPIRVData stage;
+ stage.spir_v = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_VERTEX, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
if (stage.spir_v.size() == 0) {
build_ok = false;
} else {
@@ -215,8 +242,8 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
_build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_FRAGMENT]);
current_source = builder.as_string();
- RD::ShaderStageData stage;
- stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_FRAGMENT, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
+ RD::ShaderStageSPIRVData stage;
+ stage.spir_v = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_FRAGMENT, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
if (stage.spir_v.size() == 0) {
build_ok = false;
} else {
@@ -234,8 +261,8 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
current_source = builder.as_string();
- RD::ShaderStageData stage;
- stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_COMPUTE, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
+ RD::ShaderStageSPIRVData stage;
+ stage.spir_v = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_COMPUTE, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
if (stage.spir_v.size() == 0) {
build_ok = false;
} else {
@@ -255,15 +282,20 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
return;
}
- RID shader = RD::get_singleton()->shader_create(stages);
+ Vector<uint8_t> shader_data = RD::get_singleton()->shader_compile_binary_from_spirv(stages, name + ":" + itos(p_variant));
+
+ ERR_FAIL_COND(shader_data.size() == 0);
+
+ RID shader = RD::get_singleton()->shader_create_from_bytecode(shader_data);
{
MutexLock lock(variant_set_mutex);
p_version->variants[p_variant] = shader;
+ p_version->variant_data[p_variant] = shader_data;
}
}
RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_version) {
- Version *version = version_owner.getornull(p_version);
+ Version *version = version_owner.get_or_null(p_version);
RS::ShaderNativeSourceCode source_code;
ERR_FAIL_COND_V(!version, source_code);
@@ -313,6 +345,121 @@ RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_versio
return source_code;
}
+String ShaderRD::_version_get_sha1(Version *p_version) const {
+ StringBuilder hash_build;
+
+ hash_build.append("[uniforms]");
+ hash_build.append(p_version->uniforms.get_data());
+ hash_build.append("[vertex_globals]");
+ hash_build.append(p_version->vertex_globals.get_data());
+ hash_build.append("[fragment_globals]");
+ hash_build.append(p_version->fragment_globals.get_data());
+ hash_build.append("[compute_globals]");
+ hash_build.append(p_version->compute_globals.get_data());
+
+ Vector<StringName> code_sections;
+ for (const KeyValue<StringName, CharString> &E : p_version->code_sections) {
+ code_sections.push_back(E.key);
+ }
+ code_sections.sort_custom<StringName::AlphCompare>();
+
+ for (int i = 0; i < code_sections.size(); i++) {
+ hash_build.append(String("[code:") + String(code_sections[i]) + "]");
+ hash_build.append(p_version->code_sections[code_sections[i]].get_data());
+ }
+ for (int i = 0; i < p_version->custom_defines.size(); i++) {
+ hash_build.append("[custom_defines:" + itos(i) + "]");
+ hash_build.append(p_version->custom_defines[i].get_data());
+ }
+
+ return hash_build.as_string().sha1_text();
+}
+
+static const char *shader_file_header = "GDSC";
+static const uint32_t cache_file_version = 2;
+
+bool ShaderRD::_load_from_cache(Version *p_version) {
+ String sha1 = _version_get_sha1(p_version);
+ String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
+
+ FileAccessRef f = FileAccess::open(path, FileAccess::READ);
+ if (!f) {
+ return false;
+ }
+
+ char header[5] = { 0, 0, 0, 0, 0 };
+ f->get_buffer((uint8_t *)header, 4);
+ ERR_FAIL_COND_V(header != String(shader_file_header), false);
+
+ uint32_t file_version = f->get_32();
+ if (file_version != cache_file_version) {
+ return false; // wrong version
+ }
+
+ uint32_t variant_count = f->get_32();
+
+ ERR_FAIL_COND_V(variant_count != (uint32_t)variant_defines.size(), false); //should not happen but check
+
+ for (uint32_t i = 0; i < variant_count; i++) {
+ uint32_t variant_size = f->get_32();
+ ERR_FAIL_COND_V(variant_size == 0 && variants_enabled[i], false);
+ if (!variants_enabled[i]) {
+ continue;
+ }
+ Vector<uint8_t> variant_bytes;
+ variant_bytes.resize(variant_size);
+
+ uint32_t br = f->get_buffer(variant_bytes.ptrw(), variant_size);
+
+ ERR_FAIL_COND_V(br != variant_size, false);
+
+ p_version->variant_data[i] = variant_bytes;
+ }
+
+ for (uint32_t i = 0; i < variant_count; i++) {
+ if (!variants_enabled[i]) {
+ MutexLock lock(variant_set_mutex);
+ p_version->variants[i] = RID();
+ continue;
+ }
+ RID shader = RD::get_singleton()->shader_create_from_bytecode(p_version->variant_data[i]);
+ if (shader.is_null()) {
+ for (uint32_t j = 0; j < i; j++) {
+ RD::get_singleton()->free(p_version->variants[i]);
+ }
+ ERR_FAIL_COND_V(shader.is_null(), false);
+ }
+ {
+ MutexLock lock(variant_set_mutex);
+ p_version->variants[i] = shader;
+ }
+ }
+
+ memdelete_arr(p_version->variant_data); //clear stages
+ p_version->variant_data = nullptr;
+ p_version->valid = true;
+ return true;
+}
+
+void ShaderRD::_save_to_cache(Version *p_version) {
+ String sha1 = _version_get_sha1(p_version);
+ String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
+
+ FileAccessRef f = FileAccess::open(path, FileAccess::WRITE);
+ ERR_FAIL_COND(!f);
+ f->store_buffer((const uint8_t *)shader_file_header, 4);
+ f->store_32(cache_file_version); //file version
+ uint32_t variant_count = variant_defines.size();
+ f->store_32(variant_count); //variant count
+
+ for (uint32_t i = 0; i < variant_count; i++) {
+ f->store_32(p_version->variant_data[i].size()); //stage count
+ f->store_buffer(p_version->variant_data[i].ptr(), p_version->variant_data[i].size());
+ }
+
+ f->close();
+}
+
void ShaderRD::_compile_version(Version *p_version) {
_clear_version(p_version);
@@ -320,6 +467,15 @@ void ShaderRD::_compile_version(Version *p_version) {
p_version->dirty = false;
p_version->variants = memnew_arr(RID, variant_defines.size());
+ typedef Vector<uint8_t> ShaderStageData;
+ p_version->variant_data = memnew_arr(ShaderStageData, variant_defines.size());
+
+ if (shader_cache_dir_valid) {
+ if (_load_from_cache(p_version)) {
+ return;
+ }
+ }
+
#if 1
RendererThreadPool::singleton->thread_work_pool.do_work(variant_defines.size(), this, &ShaderRD::_compile_variant, p_version);
@@ -351,24 +507,34 @@ void ShaderRD::_compile_version(Version *p_version) {
}
}
memdelete_arr(p_version->variants);
+ if (p_version->variant_data) {
+ memdelete_arr(p_version->variant_data);
+ }
p_version->variants = nullptr;
+ p_version->variant_data = nullptr;
return;
+ } else if (shader_cache_dir_valid) {
+ //save shader cache
+ _save_to_cache(p_version);
}
+ memdelete_arr(p_version->variant_data); //clear stages
+ p_version->variant_data = nullptr;
+
p_version->valid = true;
}
void ShaderRD::version_set_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines) {
ERR_FAIL_COND(is_compute);
- Version *version = version_owner.getornull(p_version);
+ Version *version = version_owner.get_or_null(p_version);
ERR_FAIL_COND(!version);
version->vertex_globals = p_vertex_globals.utf8();
version->fragment_globals = p_fragment_globals.utf8();
version->uniforms = p_uniforms.utf8();
version->code_sections.clear();
- for (Map<String, String>::Element *E = p_code.front(); E; E = E->next()) {
- version->code_sections[StringName(E->key().to_upper())] = E->get().utf8();
+ for (const KeyValue<String, String> &E : p_code) {
+ version->code_sections[StringName(E.key.to_upper())] = E.value.utf8();
}
version->custom_defines.clear();
@@ -386,15 +552,15 @@ void ShaderRD::version_set_code(RID p_version, const Map<String, String> &p_code
void ShaderRD::version_set_compute_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_compute_globals, const Vector<String> &p_custom_defines) {
ERR_FAIL_COND(!is_compute);
- Version *version = version_owner.getornull(p_version);
+ Version *version = version_owner.get_or_null(p_version);
ERR_FAIL_COND(!version);
version->compute_globals = p_compute_globals.utf8();
version->uniforms = p_uniforms.utf8();
version->code_sections.clear();
- for (Map<String, String>::Element *E = p_code.front(); E; E = E->next()) {
- version->code_sections[StringName(E->key().to_upper())] = E->get().utf8();
+ for (const KeyValue<String, String> &E : p_code) {
+ version->code_sections[StringName(E.key.to_upper())] = E.value.utf8();
}
version->custom_defines.clear();
@@ -410,7 +576,7 @@ void ShaderRD::version_set_compute_code(RID p_version, const Map<String, String>
}
bool ShaderRD::version_is_valid(RID p_version) {
- Version *version = version_owner.getornull(p_version);
+ Version *version = version_owner.get_or_null(p_version);
ERR_FAIL_COND_V(!version, false);
if (version->dirty) {
@@ -422,7 +588,7 @@ bool ShaderRD::version_is_valid(RID p_version) {
bool ShaderRD::version_free(RID p_version) {
if (version_owner.owns(p_version)) {
- Version *version = version_owner.getornull(p_version);
+ Version *version = version_owner.get_or_null(p_version);
_clear_version(version);
version_owner.free(p_version);
} else {
@@ -443,6 +609,8 @@ bool ShaderRD::is_variant_enabled(int p_variant) const {
return variants_enabled[p_variant];
}
+bool ShaderRD::shader_cache_cleanup_on_start = false;
+
ShaderRD::ShaderRD() {
// Do not feel forced to use this, in most cases it makes little to no difference.
bool use_32_threads = false;
@@ -469,8 +637,64 @@ void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String
variant_defines.push_back(p_variant_defines[i].utf8());
variants_enabled.push_back(true);
}
+
+ if (shader_cache_dir != String()) {
+ StringBuilder hash_build;
+
+ hash_build.append("[base_hash]");
+ hash_build.append(base_sha256);
+ hash_build.append("[general_defines]");
+ hash_build.append(general_defines.get_data());
+ for (int i = 0; i < variant_defines.size(); i++) {
+ hash_build.append("[variant_defines:" + itos(i) + "]");
+ hash_build.append(variant_defines[i].get_data());
+ }
+
+ base_sha256 = hash_build.as_string().sha256_text();
+
+ DirAccessRef d = DirAccess::open(shader_cache_dir);
+ ERR_FAIL_COND(!d);
+ if (d->change_dir(name) != OK) {
+ Error err = d->make_dir(name);
+ ERR_FAIL_COND(err != OK);
+ d->change_dir(name);
+ }
+
+ //erase other versions?
+ if (shader_cache_cleanup_on_start) {
+ }
+ //
+ if (d->change_dir(base_sha256) != OK) {
+ Error err = d->make_dir(base_sha256);
+ ERR_FAIL_COND(err != OK);
+ }
+ shader_cache_dir_valid = true;
+
+ print_verbose("Shader '" + name + "' SHA256: " + base_sha256);
+ }
}
+void ShaderRD::set_shader_cache_dir(const String &p_dir) {
+ shader_cache_dir = p_dir;
+}
+
+void ShaderRD::set_shader_cache_save_compressed(bool p_enable) {
+ shader_cache_save_compressed = p_enable;
+}
+
+void ShaderRD::set_shader_cache_save_compressed_zstd(bool p_enable) {
+ shader_cache_save_compressed_zstd = p_enable;
+}
+
+void ShaderRD::set_shader_cache_save_debug(bool p_enable) {
+ shader_cache_save_debug = p_enable;
+}
+
+String ShaderRD::shader_cache_dir;
+bool ShaderRD::shader_cache_save_compressed = true;
+bool ShaderRD::shader_cache_save_compressed_zstd = true;
+bool ShaderRD::shader_cache_save_debug = true;
+
ShaderRD::~ShaderRD() {
List<RID> remaining;
version_owner.get_owned_list(&remaining);
diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h
index f20d539621..984b168659 100644
--- a/servers/rendering/renderer_rd/shader_rd.h
+++ b/servers/rendering/renderer_rd/shader_rd.h
@@ -59,7 +59,8 @@ class ShaderRD {
Map<StringName, CharString> code_sections;
Vector<CharString> custom_defines;
- RID *variants; //same size as version defines
+ Vector<uint8_t> *variant_data = nullptr;
+ RID *variants = nullptr; //same size as version defines
bool valid;
bool dirty;
@@ -96,10 +97,19 @@ class ShaderRD {
bool is_compute = false;
- const char *name;
+ String name;
CharString base_compute_defines;
+ String base_sha256;
+
+ static String shader_cache_dir;
+ static bool shader_cache_cleanup_on_start;
+ static bool shader_cache_save_compressed;
+ static bool shader_cache_save_compressed_zstd;
+ static bool shader_cache_save_debug;
+ bool shader_cache_dir_valid = false;
+
enum StageType {
STAGE_TYPE_VERTEX,
STAGE_TYPE_FRAGMENT,
@@ -113,6 +123,10 @@ class ShaderRD {
void _add_stage(const char *p_code, StageType p_stage_type);
+ String _version_get_sha1(Version *p_version) const;
+ bool _load_from_cache(Version *p_version);
+ void _save_to_cache(Version *p_version);
+
protected:
ShaderRD();
void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name);
@@ -127,7 +141,7 @@ public:
ERR_FAIL_INDEX_V(p_variant, variant_defines.size(), RID());
ERR_FAIL_COND_V(!variants_enabled[p_variant], RID());
- Version *version = version_owner.getornull(p_version);
+ Version *version = version_owner.get_or_null(p_version);
ERR_FAIL_COND_V(!version, RID());
if (version->dirty) {
@@ -148,6 +162,11 @@ public:
void set_variant_enabled(int p_variant, bool p_enabled);
bool is_variant_enabled(int p_variant) const;
+ static void set_shader_cache_dir(const String &p_dir);
+ static void set_shader_cache_save_compressed(bool p_enable);
+ static void set_shader_cache_save_compressed_zstd(bool p_enable);
+ static void set_shader_cache_save_debug(bool p_enable);
+
RS::ShaderNativeSourceCode version_get_native_source_code(RID p_version);
void initialize(const Vector<String> &p_variant_defines, const String &p_general_defines = "");
diff --git a/servers/rendering/renderer_rd/shaders/blit.glsl b/servers/rendering/renderer_rd/shaders/blit.glsl
index 967da1e6e4..8051f96738 100644
--- a/servers/rendering/renderer_rd/shaders/blit.glsl
+++ b/servers/rendering/renderer_rd/shaders/blit.glsl
@@ -5,6 +5,7 @@
#VERSION_DEFINES
layout(push_constant, binding = 0, std140) uniform Pos {
+ vec4 src_rect;
vec4 dst_rect;
vec2 eye_center;
@@ -22,8 +23,8 @@ layout(location = 0) out vec2 uv;
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 = base_arr[gl_VertexIndex];
- vec2 vtx = data.dst_rect.xy + uv * data.dst_rect.zw;
+ uv = data.src_rect.xy + base_arr[gl_VertexIndex] * data.src_rect.zw;
+ vec2 vtx = data.dst_rect.xy + base_arr[gl_VertexIndex] * data.dst_rect.zw;
gl_Position = vec4(vtx * 2.0 - 1.0, 0.0, 1.0);
}
@@ -34,6 +35,7 @@ void main() {
#VERSION_DEFINES
layout(push_constant, binding = 0, std140) uniform Pos {
+ vec4 src_rect;
vec4 dst_rect;
vec2 eye_center;
diff --git a/servers/rendering/renderer_rd/shaders/blur_raster.glsl b/servers/rendering/renderer_rd/shaders/blur_raster.glsl
new file mode 100644
index 0000000000..f8b4e3f610
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/blur_raster.glsl
@@ -0,0 +1,138 @@
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "blur_raster_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];
+
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "blur_raster_inc.glsl"
+
+layout(location = 0) in vec2 uv_interp;
+/* clang-format on */
+
+layout(set = 0, binding = 0) uniform sampler2D source_color;
+
+#ifdef GLOW_USE_AUTO_EXPOSURE
+layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
+#endif
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+ // We do not apply our color scale for our mobile renderer here, we'll leave our colors at half brightness and apply scale in the tonemap raster.
+
+#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_COPY
+ vec4 color = textureLod(source_color, uv_interp, 0.0);
+ frag_color = color;
+#endif
+}
diff --git a/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl b/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl
new file mode 100644
index 0000000000..52bf2886b5
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl
@@ -0,0 +1,21 @@
+#define FLAG_HORIZONTAL (1 << 0)
+#define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 1)
+#define FLAG_GLOW_FIRST_PASS (1 << 2)
+
+layout(push_constant, binding = 1, std430) uniform Blur {
+ 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;
+}
+blur;
diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
index b70e0b6bd5..0438671dd2 100644
--- a/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
+++ b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
@@ -25,34 +25,7 @@ layout(set = 1, binding = 0) uniform sampler2D source_bokeh;
// based on https://www.shadertoy.com/view/Xd3GDl
-layout(push_constant, binding = 1, std430) uniform Params {
- ivec2 size;
- float z_far;
- float z_near;
-
- bool orthogonal;
- float blur_size;
- float blur_scale;
- int blur_steps;
-
- bool blur_near_active;
- float blur_near_begin;
- float blur_near_end;
- bool blur_far_active;
-
- float blur_far_begin;
- float blur_far_end;
- bool second_pass;
- bool half_size;
-
- bool use_jitter;
- float jitter_seed;
- uint pad[2];
-}
-params;
-
-//used to work around downsampling filter
-#define DEPTH_GAP 0.0
+#include "bokeh_dof_inc.glsl"
#ifdef MODE_GEN_BLUR_SIZE
@@ -80,15 +53,6 @@ float get_blur_size(float depth) {
#endif
-const float GOLDEN_ANGLE = 2.39996323;
-
-//note: uniform pdf rand [0;1[
-float hash12n(vec2 p) {
- p = fract(p * vec2(5.3987, 5.4421));
- p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
- return fract(p.x * p.y * 95.4307);
-}
-
#if defined(MODE_BOKEH_BOX) || defined(MODE_BOKEH_HEXAGONAL)
vec4 weighted_filter_dir(vec2 dir, vec2 uv, vec2 pixel_size) {
diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl
new file mode 100644
index 0000000000..fadea1631c
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl
@@ -0,0 +1,37 @@
+layout(push_constant, binding = 1, std430) uniform Params {
+ ivec2 size;
+ float z_far;
+ float z_near;
+
+ bool orthogonal;
+ float blur_size;
+ float blur_scale;
+ int blur_steps;
+
+ bool blur_near_active;
+ float blur_near_begin;
+ float blur_near_end;
+ bool blur_far_active;
+
+ float blur_far_begin;
+ float blur_far_end;
+ bool second_pass;
+ bool half_size;
+
+ bool use_jitter;
+ float jitter_seed;
+ uint pad[2];
+}
+params;
+
+//used to work around downsampling filter
+#define DEPTH_GAP 0.0
+
+const float GOLDEN_ANGLE = 2.39996323;
+
+//note: uniform pdf rand [0;1[
+float hash12n(vec2 p) {
+ p = fract(p * vec2(5.3987, 5.4421));
+ p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
+ return fract(p.x * p.y * 95.4307);
+}
diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl
new file mode 100644
index 0000000000..a3b3938ee9
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl
@@ -0,0 +1,253 @@
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "bokeh_dof_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];
+
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "bokeh_dof_inc.glsl"
+
+layout(location = 0) in vec2 uv_interp;
+/* clang-format on */
+
+#ifdef MODE_GEN_BLUR_SIZE
+layout(location = 0) out float weight;
+
+layout(set = 0, binding = 0) uniform sampler2D source_depth;
+#else
+layout(location = 0) out vec4 frag_color;
+#ifdef OUTPUT_WEIGHT
+layout(location = 1) out float weight;
+#endif
+
+layout(set = 0, binding = 0) uniform sampler2D source_color;
+layout(set = 1, binding = 0) uniform sampler2D source_weight;
+#ifdef MODE_COMPOSITE_BOKEH
+layout(set = 2, binding = 0) uniform sampler2D original_weight;
+#endif
+#endif
+
+//DOF
+// Bokeh single pass implementation based on https://tuxedolabs.blogspot.com/2018/05/bokeh-depth-of-field-in-single-pass.html
+
+#ifdef MODE_GEN_BLUR_SIZE
+
+float get_depth_at_pos(vec2 uv) {
+ float depth = textureLod(source_depth, uv, 0.0).x;
+ if (params.orthogonal) {
+ depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0;
+ } else {
+ depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near));
+ }
+ return depth;
+}
+
+float get_blur_size(float depth) {
+ if (params.blur_near_active && depth < params.blur_near_begin) {
+ return -(1.0 - smoothstep(params.blur_near_end, params.blur_near_begin, depth)) * params.blur_size - DEPTH_GAP; //near blur is negative
+ }
+
+ if (params.blur_far_active && depth > params.blur_far_begin) {
+ return smoothstep(params.blur_far_begin, params.blur_far_end, depth) * params.blur_size + DEPTH_GAP;
+ }
+
+ return 0.0;
+}
+
+#endif
+
+#if defined(MODE_BOKEH_BOX) || defined(MODE_BOKEH_HEXAGONAL)
+
+vec4 weighted_filter_dir(vec2 dir, vec2 uv, vec2 pixel_size) {
+ dir *= pixel_size;
+ vec4 color = texture(source_color, uv);
+ color.a = texture(source_weight, uv).r;
+
+ vec4 accum = color;
+ float total = 1.0;
+
+ float blur_scale = params.blur_size / float(params.blur_steps);
+
+ if (params.use_jitter) {
+ uv += dir * (hash12n(uv + params.jitter_seed) - 0.5);
+ }
+
+ for (int i = -params.blur_steps; i <= params.blur_steps; i++) {
+ if (i == 0) {
+ continue;
+ }
+ float radius = float(i) * blur_scale;
+ vec2 suv = uv + dir * radius;
+ radius = abs(radius);
+
+ vec4 sample_color = texture(source_color, suv);
+ sample_color.a = texture(source_weight, suv).r;
+ float limit;
+
+ if (sample_color.a < color.a) {
+ limit = abs(sample_color.a);
+ } else {
+ limit = abs(color.a);
+ }
+
+ limit -= DEPTH_GAP;
+
+ float m = smoothstep(radius - 0.5, radius + 0.5, limit);
+
+ accum += mix(color, sample_color, m);
+
+ total += 1.0;
+ }
+
+ return accum / total;
+}
+
+#endif
+
+void main() {
+ vec2 pixel_size = 1.0 / vec2(params.size);
+ vec2 uv = uv_interp;
+
+#ifdef MODE_GEN_BLUR_SIZE
+ uv += pixel_size * 0.5;
+ float center_depth = get_depth_at_pos(uv);
+ weight = get_blur_size(center_depth);
+#endif
+
+#ifdef MODE_BOKEH_BOX
+ //pixel_size*=0.5; //resolution is doubled
+ if (params.second_pass || !params.half_size) {
+ uv += pixel_size * 0.5; //half pixel to read centers
+ } else {
+ uv += pixel_size * 0.25; //half pixel to read centers from full res
+ }
+
+ float alpha = texture(source_color, uv).a; // retain this
+ vec2 dir = (params.second_pass ? vec2(0.0, 1.0) : vec2(1.0, 0.0));
+
+ vec4 color = weighted_filter_dir(dir, uv, pixel_size);
+
+ frag_color = color;
+ frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size
+#ifdef OUTPUT_WEIGHT
+ weight = color.a;
+#endif
+
+#endif
+
+#ifdef MODE_BOKEH_HEXAGONAL
+
+ //pixel_size*=0.5; //resolution is doubled
+ if (params.second_pass || !params.half_size) {
+ uv += pixel_size * 0.5; //half pixel to read centers
+ } else {
+ uv += pixel_size * 0.25; //half pixel to read centers from full res
+ }
+
+ float alpha = texture(source_color, uv).a; // retain this
+
+ vec2 dir = (params.second_pass ? normalize(vec2(1.0, 0.577350269189626)) : vec2(0.0, 1.0));
+
+ vec4 color = weighted_filter_dir(dir, uv, pixel_size);
+
+ if (params.second_pass) {
+ dir = normalize(vec2(-1.0, 0.577350269189626));
+
+ vec4 color2 = weighted_filter_dir(dir, uv, pixel_size);
+
+ color.rgb = min(color.rgb, color2.rgb);
+ color.a = (color.a + color2.a) * 0.5;
+ }
+
+ frag_color = color;
+ frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size
+#ifdef OUTPUT_WEIGHT
+ weight = color.a;
+#endif
+
+#endif
+
+#ifdef MODE_BOKEH_CIRCULAR
+ if (params.half_size) {
+ pixel_size *= 0.5; //resolution is doubled
+ }
+
+ uv += pixel_size * 0.5; //half pixel to read centers
+
+ vec4 color = texture(source_color, uv);
+ float alpha = color.a; // retain this
+ color.a = texture(source_weight, uv).r;
+
+ vec4 color_accum = color;
+ float accum = 1.0;
+
+ float radius = params.blur_scale;
+ for (float ang = 0.0; radius < params.blur_size; ang += GOLDEN_ANGLE) {
+ vec2 uv_adj = uv + vec2(cos(ang), sin(ang)) * pixel_size * radius;
+
+ vec4 sample_color = texture(source_color, uv_adj);
+ sample_color.a = texture(source_weight, uv_adj).r;
+
+ float limit;
+
+ if (sample_color.a < color.a) {
+ limit = abs(sample_color.a);
+ } else {
+ limit = abs(color.a);
+ }
+
+ limit -= DEPTH_GAP;
+
+ float m = smoothstep(radius - 0.5, radius + 0.5, limit);
+ color_accum += mix(color_accum / accum, sample_color, m);
+ accum += 1.0;
+
+ radius += params.blur_scale / radius;
+ }
+
+ color_accum = color_accum / accum;
+
+ frag_color.rgb = color_accum.rgb;
+ frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size
+#ifdef OUTPUT_WEIGHT
+ weight = color_accum.a;
+#endif
+
+#endif
+
+#ifdef MODE_COMPOSITE_BOKEH
+ frag_color.rgb = texture(source_color, uv).rgb;
+
+ float center_weigth = texture(source_weight, uv).r;
+ float sample_weight = texture(original_weight, uv).r;
+
+ float mix_amount;
+ if (sample_weight < center_weigth) {
+ mix_amount = min(1.0, max(0.0, max(abs(center_weigth), abs(sample_weight)) - DEPTH_GAP));
+ } else {
+ mix_amount = min(1.0, max(0.0, abs(center_weigth) - DEPTH_GAP));
+ }
+
+ // let alpha blending take care of mixing
+ frag_color.a = mix_amount;
+#endif
+}
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index cf4c77db0d..65a621b203 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -65,7 +65,7 @@ void main() {
#elif defined(USE_ATTRIBUTES)
vec2 vertex = vertex_attrib;
- vec4 color = color_attrib;
+ vec4 color = color_attrib * draw_data.modulation;
vec2 uv = uv_attrib;
uvec4 bones = bone_attrib;
@@ -91,7 +91,6 @@ void main() {
uint instancing = draw_data.flags & FLAGS_INSTANCING_MASK;
#ifdef USE_ATTRIBUTES
-
if (instancing > 1) {
// trails
@@ -101,66 +100,64 @@ void main() {
uint offset = trail_size * stride * gl_InstanceIndex;
- mat4 matrix;
vec4 pcolor;
+ vec2 new_vertex;
{
uint boffset = offset + bone_attrib.x * stride;
- matrix = mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.x;
- pcolor = transforms.data[boffset + 3] * weight_attrib.x;
+ new_vertex = (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.x;
+ pcolor = transforms.data[boffset + 2] * weight_attrib.x;
}
if (weight_attrib.y > 0.001) {
uint boffset = offset + bone_attrib.y * stride;
- matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.y;
- pcolor += transforms.data[boffset + 3] * weight_attrib.y;
+ new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.y;
+ pcolor += transforms.data[boffset + 2] * weight_attrib.y;
}
if (weight_attrib.z > 0.001) {
uint boffset = offset + bone_attrib.z * stride;
- matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.z;
- pcolor += transforms.data[boffset + 3] * weight_attrib.z;
+ new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.z;
+ pcolor += transforms.data[boffset + 2] * weight_attrib.z;
}
if (weight_attrib.w > 0.001) {
uint boffset = offset + bone_attrib.w * stride;
- matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.w;
- pcolor += transforms.data[boffset + 3] * weight_attrib.w;
+ new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.w;
+ pcolor += transforms.data[boffset + 2] * weight_attrib.w;
}
- instance_custom = transforms.data[offset + 4];
+ instance_custom = transforms.data[offset + 3];
+ vertex = new_vertex;
color *= pcolor;
-
- matrix = transpose(matrix);
- world_matrix = world_matrix * matrix;
-
} else
#endif // USE_ATTRIBUTES
+ {
+ if (instancing == 1) {
+ uint stride = 2;
+ {
+ if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
+ stride += 1;
+ }
+ if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
+ stride += 1;
+ }
+ }
+
+ uint offset = stride * gl_InstanceIndex;
+
+ mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
+ offset += 2;
- if (instancing == 1) {
- uint stride = 2;
- {
if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
- stride += 1;
+ color *= transforms.data[offset];
+ offset += 1;
}
+
if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
- stride += 1;
+ instance_custom = transforms.data[offset];
}
- }
- uint offset = stride * gl_InstanceIndex;
-
- mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
- offset += 2;
-
- if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
- color *= transforms.data[offset];
- offset += 1;
+ matrix = transpose(matrix);
+ world_matrix = world_matrix * matrix;
}
-
- if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
- instance_custom = transforms.data[offset];
- }
-
- matrix = transpose(matrix);
- world_matrix = world_matrix * matrix;
}
#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
@@ -283,7 +280,7 @@ vec2 screen_uv_to_sdf(vec2 p_uv) {
float texture_sdf(vec2 p_sdf) {
vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw;
float d = texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv).r;
- d = d * SDF_MAX_LENGTH - 1.0;
+ d *= SDF_MAX_LENGTH;
return d * canvas_data.tex_to_sdf;
}
@@ -460,6 +457,14 @@ void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) {
#endif
+float msdf_median(float r, float g, float b, float a) {
+ return min(max(min(r, g), min(max(r, g), b)), a);
+}
+
+vec2 msdf_map(vec2 value, vec2 in_min, vec2 in_max, vec2 out_min, vec2 out_max) {
+ return out_min + (out_max - out_min) * (value - in_min) / (in_max - in_min);
+}
+
void main() {
vec4 color = color_interp;
vec2 uv = uv_interp;
@@ -487,7 +492,34 @@ void main() {
#endif
- color *= texture(sampler2D(color_texture, texture_sampler), uv);
+#ifndef USE_PRIMITIVE
+ if (bool(draw_data.flags & FLAGS_USE_MSDF)) {
+ float px_range = draw_data.ninepatch_margins.x;
+ float outline_thickness = draw_data.ninepatch_margins.y;
+ //float reserved1 = draw_data.ninepatch_margins.z;
+ //float reserved2 = draw_data.ninepatch_margins.w;
+
+ vec4 msdf_sample = texture(sampler2D(color_texture, texture_sampler), uv);
+ vec2 msdf_size = vec2(textureSize(sampler2D(color_texture, texture_sampler), 0));
+ vec2 dest_size = vec2(1.0) / fwidth(uv);
+ float px_size = max(0.5 * dot((vec2(px_range) / msdf_size), dest_size), 1.0);
+ float d = msdf_median(msdf_sample.r, msdf_sample.g, msdf_sample.b, msdf_sample.a) - 0.5;
+
+ if (outline_thickness > 0) {
+ float cr = clamp(outline_thickness, 0.0, px_range / 2) / px_range;
+ float a = clamp((d + cr) * px_size, 0.0, 1.0);
+ color.a = a * color.a;
+ } else {
+ float a = clamp(d * px_size + 0.5, 0.0, 1.0);
+ color.a = a * color.a;
+ }
+
+ } else {
+#else
+ {
+#endif
+ color *= texture(sampler2D(color_texture, texture_sampler), uv);
+ }
uint light_count = (draw_data.flags >> FLAGS_LIGHT_COUNT_SHIFT) & 0xF; //max 16 lights
bool using_light = light_count > 0 || canvas_data.directional_light_count > 0;
diff --git a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
index 65a554e839..2bdfbabfcf 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
@@ -7,7 +7,7 @@
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(r8, set = 0, binding = 1) uniform restrict readonly image2D src_pixels;
-layout(r16, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf;
+layout(r16_snorm, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf;
layout(rg16i, set = 0, binding = 3) uniform restrict readonly iimage2D src_process;
layout(rg16i, set = 0, binding = 4) uniform restrict writeonly iimage2D dst_process;
@@ -32,7 +32,7 @@ void main() {
#ifdef MODE_LOAD
bool solid = imageLoad(src_pixels, pos).r > 0.5;
- imageStore(dst_process, pos, solid ? ivec4(pos, 0, 0) : ivec4(ivec2(32767), 0, 0));
+ imageStore(dst_process, pos, solid ? ivec4(ivec2(-32767), 0, 0) : ivec4(ivec2(32767), 0, 0));
#endif
#ifdef MODE_LOAD_SHRINK
@@ -43,6 +43,8 @@ void main() {
ivec2 rel = ivec2(32767);
float d = 1e20;
+ int found = 0;
+ int solid_found = 0;
for (int i = 0; i < s; i++) {
for (int j = 0; j < s; j++) {
ivec2 src_pos = base + ivec2(i, j);
@@ -56,10 +58,17 @@ void main() {
d = dist;
rel = src_pos;
}
+ solid_found++;
}
+ found++;
}
}
+ if (solid_found == found) {
+ //mark solid only if all are solid
+ rel = ivec2(-32767);
+ }
+
imageStore(dst_process, pos, ivec4(rel, 0, 0));
#endif
@@ -70,6 +79,12 @@ void main() {
ivec2 rel = imageLoad(src_process, pos).xy;
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
if (center != rel) {
//only process if it does not point to itself
const int ofs_table_size = 8;
@@ -92,6 +107,15 @@ void main() {
continue;
}
ivec2 src_rel = imageLoad(src_process, src_pos).xy;
+ bool src_solid = src_rel.x < 0;
+ if (src_solid) {
+ src_rel = -src_rel - ivec2(1);
+ }
+
+ if (src_solid != solid) {
+ src_rel = ivec2(src_pos << params.shift); //point to itself if of different type
+ }
+
float src_dist = length(vec2(src_rel - center));
if (src_dist < dist) {
dist = src_dist;
@@ -100,18 +124,31 @@ void main() {
}
}
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
imageStore(dst_process, pos, ivec4(rel, 0, 0));
#endif
#ifdef MODE_STORE
ivec2 rel = imageLoad(src_process, pos).xy;
+
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
float d = length(vec2(rel - pos));
- if (d > 0.01) {
- d += 1.0; //make it signed
+
+ if (solid) {
+ d = -d;
}
+
d /= SDF_MAX_LENGTH;
- d = clamp(d, 0.0, 1.0);
+ d = clamp(d, -1.0, 1.0);
imageStore(dst_sdf, pos, vec4(d));
#endif
@@ -122,13 +159,20 @@ void main() {
ivec2 center = base + ivec2(params.shift);
ivec2 rel = imageLoad(src_process, pos).xy;
+
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
float d = length(vec2(rel - center));
- if (d > 0.01) {
- d += 1.0; //make it signed
+ if (solid) {
+ d = -d;
}
d /= SDF_MAX_LENGTH;
- d = clamp(d, 0.0, 1.0);
+ d = clamp(d, -1.0, 1.0);
imageStore(dst_sdf, pos, vec4(d));
#endif
diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
index 451f9b0089..0cff505cae 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
@@ -24,6 +24,8 @@
#define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26)
#define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27)
+#define FLAGS_USE_MSDF (1 << 28)
+
#define SAMPLER_NEAREST_CLAMP 0
#define SAMPLER_LINEAR_CLAMP 1
#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
diff --git a/servers/rendering/renderer_rd/shaders/cluster_render.glsl b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
index da7d189281..6d95722a57 100644
--- a/servers/rendering/renderer_rd/shaders/cluster_render.glsl
+++ b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
@@ -117,7 +117,7 @@ void main() {
uint cluster_thread_group_index;
if (!gl_HelperInvocation) {
- //http://advances.realtimerendering.com/s2017/2017_Sig_Improved_Culling_final.pdf
+ //https://advances.realtimerendering.com/s2017/2017_Sig_Improved_Culling_final.pdf
uvec4 mask;
diff --git a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
index dfbce29119..69b895ed29 100644
--- a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
+++ b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
@@ -7,8 +7,7 @@
layout(push_constant, binding = 1, std430) uniform Params {
float z_far;
float z_near;
- bool z_flip;
- uint pad;
+ vec2 texel_size;
vec4 screen_rect;
}
params;
@@ -35,22 +34,23 @@ layout(set = 0, binding = 0) uniform samplerCube source_cube;
layout(push_constant, binding = 1, std430) uniform Params {
float z_far;
float z_near;
- bool z_flip;
- uint pad;
+ vec2 texel_size;
vec4 screen_rect;
}
params;
void main() {
vec2 uv = uv_interp;
+ vec2 texel_size = abs(params.texel_size);
- vec3 normal = vec3(uv * 2.0 - 1.0, 0.0);
+ uv = clamp(uv * (1.0 + 2.0 * texel_size) - texel_size, vec2(0.0), vec2(1.0));
- normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y));
+ vec3 normal = vec3(uv * 2.0 - 1.0, 0.0);
+ normal.z = 0.5 * (1.0 - dot(normal.xy, normal.xy)); // z = 1/2 - 1/2 * (x^2 + y^2)
normal = normalize(normal);
normal.y = -normal.y; //needs to be flipped to match projection matrix
- if (!params.z_flip) {
+ if (params.texel_size.x >= 0.0) { // Sign is used to encode Z flip
normal.z = -normal.z;
}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
index 9fa84657d1..63f0ce690e 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
+++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
@@ -32,53 +32,7 @@ layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
-layout(push_constant, binding = 1, std430) uniform Params {
- uint face_size;
-}
-params;
-
-#define M_PI 3.14159265359
-
-void get_dir_0(out vec3 dir, in float u, in float v) {
- dir[0] = 1.0;
- dir[1] = v;
- dir[2] = -u;
-}
-
-void get_dir_1(out vec3 dir, in float u, in float v) {
- dir[0] = -1.0;
- dir[1] = v;
- dir[2] = u;
-}
-
-void get_dir_2(out vec3 dir, in float u, in float v) {
- dir[0] = u;
- dir[1] = 1.0;
- dir[2] = -v;
-}
-
-void get_dir_3(out vec3 dir, in float u, in float v) {
- dir[0] = u;
- dir[1] = -1.0;
- dir[2] = v;
-}
-
-void get_dir_4(out vec3 dir, in float u, in float v) {
- dir[0] = u;
- dir[1] = v;
- dir[2] = 1.0;
-}
-
-void get_dir_5(out vec3 dir, in float u, in float v) {
- dir[0] = -u;
- dir[1] = v;
- dir[2] = -1.0;
-}
-
-float calcWeight(float u, float v) {
- float val = u * u + v * v + 1.0;
- return val * sqrt(val);
-}
+#include "cubemap_downsampler_inc.glsl"
void main() {
uvec3 id = gl_GlobalInvocationID;
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl
new file mode 100644
index 0000000000..b329e67293
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl
@@ -0,0 +1,48 @@
+layout(push_constant, binding = 1, std430) uniform Params {
+ uint face_size;
+ uint face_id; // only used in raster shader
+}
+params;
+
+#define M_PI 3.14159265359
+
+void get_dir_0(out vec3 dir, in float u, in float v) {
+ dir[0] = 1.0;
+ dir[1] = v;
+ dir[2] = -u;
+}
+
+void get_dir_1(out vec3 dir, in float u, in float v) {
+ dir[0] = -1.0;
+ dir[1] = v;
+ dir[2] = u;
+}
+
+void get_dir_2(out vec3 dir, in float u, in float v) {
+ dir[0] = u;
+ dir[1] = 1.0;
+ dir[2] = -v;
+}
+
+void get_dir_3(out vec3 dir, in float u, in float v) {
+ dir[0] = u;
+ dir[1] = -1.0;
+ dir[2] = v;
+}
+
+void get_dir_4(out vec3 dir, in float u, in float v) {
+ dir[0] = u;
+ dir[1] = v;
+ dir[2] = 1.0;
+}
+
+void get_dir_5(out vec3 dir, in float u, in float v) {
+ dir[0] = -u;
+ dir[1] = v;
+ dir[2] = -1.0;
+}
+
+float calcWeight(float u, float v) {
+ float val = u * u + v * v + 1.0;
+ return val * sqrt(val);
+}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl
new file mode 100644
index 0000000000..0828ffd921
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl
@@ -0,0 +1,163 @@
+// Copyright 2016 Activision Publishing, Inc.
+//
+// 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.
+
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_downsampler_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] * float(params.face_size);
+ gl_Position = vec4(base_arr[gl_VertexIndex] * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_downsampler_inc.glsl"
+
+layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
+
+layout(location = 0) in vec2 uv_interp;
+layout(location = 0) out vec4 frag_color;
+/* clang-format on */
+
+void main() {
+ // Converted from compute shader which uses absolute coordinates.
+ // Could possibly simplify this
+ float face_size = float(params.face_size);
+
+ if (uv_interp.x < face_size && uv_interp.y < face_size) {
+ float inv_face_size = 1.0 / face_size;
+
+ float u0 = (uv_interp.x * 2.0 + 1.0 - 0.75) * inv_face_size - 1.0;
+ float u1 = (uv_interp.x * 2.0 + 1.0 + 0.75) * inv_face_size - 1.0;
+
+ float v0 = (uv_interp.y * 2.0 + 1.0 - 0.75) * -inv_face_size + 1.0;
+ float v1 = (uv_interp.y * 2.0 + 1.0 + 0.75) * -inv_face_size + 1.0;
+
+ float weights[4];
+ weights[0] = calcWeight(u0, v0);
+ weights[1] = calcWeight(u1, v0);
+ weights[2] = calcWeight(u0, v1);
+ weights[3] = calcWeight(u1, v1);
+
+ const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]);
+ for (int i = 0; i < 4; i++) {
+ weights[i] = weights[i] * wsum + .125;
+ }
+
+ vec3 dir;
+ vec4 color;
+ switch (params.face_id) {
+ case 0:
+ get_dir_0(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_0(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_0(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_0(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 1:
+ get_dir_1(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_1(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_1(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_1(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 2:
+ get_dir_2(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_2(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_2(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_2(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 3:
+ get_dir_3(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_3(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_3(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_3(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 4:
+ get_dir_4(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_4(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_4(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_4(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ default:
+ get_dir_5(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_5(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_5(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_5(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ }
+ frag_color = color;
+ }
+}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl b/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl
new file mode 100644
index 0000000000..324d306218
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl
@@ -0,0 +1,256 @@
+// Copyright 2016 Activision Publishing, Inc.
+//
+// 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.
+
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ int mip_level;
+ uint face_id;
+}
+params;
+
+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];
+ gl_Position = vec4(base_arr[gl_VertexIndex] * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ int mip_level;
+ uint face_id;
+}
+params;
+
+layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
+
+layout(location = 0) in vec2 uv_interp;
+layout(location = 0) out vec4 frag_color;
+
+/* clang-format on */
+
+#ifdef USE_HIGH_QUALITY
+#define NUM_TAPS 32
+#else
+#define NUM_TAPS 8
+#endif
+
+#define BASE_RESOLUTION 128
+
+#ifdef USE_HIGH_QUALITY
+layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
+ vec4[7][5][3][24] coeffs;
+}
+data;
+#else
+layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
+ vec4[7][5][6] coeffs;
+}
+data;
+#endif
+
+void get_dir(out vec3 dir, in vec2 uv, in uint face) {
+ switch (face) {
+ case 0:
+ dir = vec3(1.0, uv[1], -uv[0]);
+ break;
+ case 1:
+ dir = vec3(-1.0, uv[1], uv[0]);
+ break;
+ case 2:
+ dir = vec3(uv[0], 1.0, -uv[1]);
+ break;
+ case 3:
+ dir = vec3(uv[0], -1.0, uv[1]);
+ break;
+ case 4:
+ dir = vec3(uv[0], uv[1], 1.0);
+ break;
+ default:
+ dir = vec3(-uv[0], uv[1], -1.0);
+ break;
+ }
+}
+
+void main() {
+ // determine dir / pos for the texel
+ vec3 dir, adir, frameZ;
+ {
+ vec2 uv;
+ uv.x = uv_interp.x;
+ uv.y = 1.0 - uv_interp.y;
+ uv = uv * 2.0 - 1.0;
+
+ get_dir(dir, uv, params.face_id);
+ frameZ = normalize(dir);
+
+ adir = abs(dir);
+ }
+
+ // determine which texel this is
+ // NOTE (macOS/MoltenVK): Do not rename, "level" variable name conflicts with the Metal "level(float lod)" mipmap sampling function name.
+ int mip_level = 0;
+
+ if (params.mip_level < 0) {
+ // return as is
+ frag_color.rgb = textureLod(source_cubemap, frameZ, 0.0).rgb;
+ frag_color.a = 1.0;
+ return;
+ } else if (params.mip_level > 6) {
+ // maximum level
+ mip_level = 6;
+ } else {
+ mip_level = params.mip_level;
+ }
+
+ // GGX gather colors
+ vec4 color = vec4(0.0);
+ for (int axis = 0; axis < 3; axis++) {
+ const int otherAxis0 = 1 - (axis & 1) - (axis >> 1);
+ const int otherAxis1 = 2 - (axis >> 1);
+
+ float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - .75) / .25;
+ if (frameweight > 0.0) {
+ // determine frame
+ vec3 UpVector;
+ switch (axis) {
+ case 0:
+ UpVector = vec3(1, 0, 0);
+ break;
+ case 1:
+ UpVector = vec3(0, 1, 0);
+ break;
+ default:
+ UpVector = vec3(0, 0, 1);
+ break;
+ }
+
+ vec3 frameX = normalize(cross(UpVector, frameZ));
+ vec3 frameY = cross(frameZ, frameX);
+
+ // calculate parametrization for polynomial
+ float Nx = dir[otherAxis0];
+ float Ny = dir[otherAxis1];
+ float Nz = adir[axis];
+
+ float NmaxXY = max(abs(Ny), abs(Nx));
+ Nx /= NmaxXY;
+ Ny /= NmaxXY;
+
+ float theta;
+ if (Ny < Nx) {
+ if (Ny <= -0.999)
+ theta = Nx;
+ else
+ theta = Ny;
+ } else {
+ if (Ny >= 0.999)
+ theta = -Nx;
+ else
+ theta = -Ny;
+ }
+
+ float phi;
+ if (Nz <= -0.999)
+ phi = -NmaxXY;
+ else if (Nz >= 0.999)
+ phi = NmaxXY;
+ else
+ phi = Nz;
+
+ float theta2 = theta * theta;
+ float phi2 = phi * phi;
+
+ // sample
+ for (int iSuperTap = 0; iSuperTap < NUM_TAPS / 4; iSuperTap++) {
+ const int index = (NUM_TAPS / 4) * axis + iSuperTap;
+
+#ifdef USE_HIGH_QUALITY
+ vec4 coeffsDir0[3];
+ vec4 coeffsDir1[3];
+ vec4 coeffsDir2[3];
+ vec4 coeffsLevel[3];
+ vec4 coeffsWeight[3];
+
+ for (int iCoeff = 0; iCoeff < 3; iCoeff++) {
+ coeffsDir0[iCoeff] = data.coeffs[mip_level][0][iCoeff][index];
+ coeffsDir1[iCoeff] = data.coeffs[mip_level][1][iCoeff][index];
+ coeffsDir2[iCoeff] = data.coeffs[mip_level][2][iCoeff][index];
+ coeffsLevel[iCoeff] = data.coeffs[mip_level][3][iCoeff][index];
+ coeffsWeight[iCoeff] = data.coeffs[mip_level][4][iCoeff][index];
+ }
+
+ for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
+ // determine sample attributes (dir, weight, mip_level)
+ vec3 sample_dir = frameX * (coeffsDir0[0][iSubTap] + coeffsDir0[1][iSubTap] * theta2 + coeffsDir0[2][iSubTap] * phi2) + frameY * (coeffsDir1[0][iSubTap] + coeffsDir1[1][iSubTap] * theta2 + coeffsDir1[2][iSubTap] * phi2) + frameZ * (coeffsDir2[0][iSubTap] + coeffsDir2[1][iSubTap] * theta2 + coeffsDir2[2][iSubTap] * phi2);
+
+ float sample_level = coeffsLevel[0][iSubTap] + coeffsLevel[1][iSubTap] * theta2 + coeffsLevel[2][iSubTap] * phi2;
+
+ float sample_weight = coeffsWeight[0][iSubTap] + coeffsWeight[1][iSubTap] * theta2 + coeffsWeight[2][iSubTap] * phi2;
+#else
+ vec4 coeffsDir0 = data.coeffs[mip_level][0][index];
+ vec4 coeffsDir1 = data.coeffs[mip_level][1][index];
+ vec4 coeffsDir2 = data.coeffs[mip_level][2][index];
+ vec4 coeffsLevel = data.coeffs[mip_level][3][index];
+ vec4 coeffsWeight = data.coeffs[mip_level][4][index];
+
+ for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
+ // determine sample attributes (dir, weight, mip_level)
+ vec3 sample_dir = frameX * coeffsDir0[iSubTap] + frameY * coeffsDir1[iSubTap] + frameZ * coeffsDir2[iSubTap];
+
+ float sample_level = coeffsLevel[iSubTap];
+
+ float sample_weight = coeffsWeight[iSubTap];
+#endif
+
+ sample_weight *= frameweight;
+
+ // adjust for jacobian
+ sample_dir /= max(abs(sample_dir[0]), max(abs(sample_dir[1]), abs(sample_dir[2])));
+ sample_level += 0.75 * log2(dot(sample_dir, sample_dir));
+ // sample cubemap
+ color.xyz += textureLod(source_cubemap, normalize(sample_dir), sample_level).xyz * sample_weight;
+ color.w += sample_weight;
+ }
+ }
+ }
+ }
+ color /= color.w;
+
+ // write color
+ color.xyz = max(vec3(0.0), color.xyz);
+ color.w = 1.0;
+
+ frag_color = color;
+}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
index ce7c03c1d4..28f4dc59ec 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
+++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
@@ -12,100 +12,7 @@ layout(set = 0, binding = 0) uniform samplerCube source_cube;
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
-layout(push_constant, binding = 1, std430) uniform Params {
- uint face_id;
- uint sample_count;
- float roughness;
- bool use_direct_write;
- float face_size;
-}
-params;
-
-#define M_PI 3.14159265359
-
-vec3 texelCoordToVec(vec2 uv, uint faceID) {
- mat3 faceUvVectors[6];
-
- // -x
- faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
- faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
-
- // +x
- faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
- faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
-
- // -y
- faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
- faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
-
- // +y
- faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
- faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
-
- // -z
- faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
- faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
-
- // +z
- faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
-
- // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
- vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
- return normalize(result);
-}
-
-vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
- float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
-
- // Compute distribution direction
- float Phi = 2.0 * M_PI * Xi.x;
- float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
- float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
-
- // Convert to spherical direction
- vec3 H;
- H.x = SinTheta * cos(Phi);
- H.y = SinTheta * sin(Phi);
- H.z = CosTheta;
-
- vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
- vec3 TangentX = normalize(cross(UpVector, N));
- vec3 TangentY = cross(N, TangentX);
-
- // Tangent to world space
- return TangentX * H.x + TangentY * H.y + N * H.z;
-}
-
-// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
-float GGX(float NdotV, float a) {
- float k = a / 2.0;
- return NdotV / (NdotV * (1.0 - k) + k);
-}
-
-// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
-float G_Smith(float a, float nDotV, float nDotL) {
- return GGX(nDotL, a * a) * GGX(nDotV, a * a);
-}
-
-float radicalInverse_VdC(uint bits) {
- bits = (bits << 16u) | (bits >> 16u);
- bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
- bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
- bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
- bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
- return float(bits) * 2.3283064365386963e-10; // / 0x100000000
-}
-
-vec2 Hammersley(uint i, uint N) {
- return vec2(float(i) / float(N), radicalInverse_VdC(i));
-}
+#include "cubemap_roughness_inc.glsl"
void main() {
uvec3 id = gl_GlobalInvocationID;
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl
new file mode 100644
index 0000000000..be12be5dec
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl
@@ -0,0 +1,94 @@
+#define M_PI 3.14159265359
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ uint face_id;
+ uint sample_count;
+ float roughness;
+ bool use_direct_write;
+ float face_size;
+}
+params;
+
+vec3 texelCoordToVec(vec2 uv, uint faceID) {
+ mat3 faceUvVectors[6];
+
+ // -x
+ faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
+ faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
+
+ // +x
+ faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
+ faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
+
+ // -y
+ faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
+ faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
+
+ // +y
+ faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
+ faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
+
+ // -z
+ faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
+ faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
+
+ // +z
+ faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
+
+ // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
+ vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
+ return normalize(result);
+}
+
+vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
+ float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
+
+ // Compute distribution direction
+ float Phi = 2.0 * M_PI * Xi.x;
+ float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
+ float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
+
+ // Convert to spherical direction
+ vec3 H;
+ H.x = SinTheta * cos(Phi);
+ H.y = SinTheta * sin(Phi);
+ H.z = CosTheta;
+
+ vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
+ vec3 TangentX = normalize(cross(UpVector, N));
+ vec3 TangentY = cross(N, TangentX);
+
+ // Tangent to world space
+ return TangentX * H.x + TangentY * H.y + N * H.z;
+}
+
+// https://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+float GGX(float NdotV, float a) {
+ float k = a / 2.0;
+ return NdotV / (NdotV * (1.0 - k) + k);
+}
+
+// https://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+float G_Smith(float a, float nDotV, float nDotL) {
+ return GGX(nDotL, a * a) * GGX(nDotV, a * a);
+}
+
+float radicalInverse_VdC(uint bits) {
+ bits = (bits << 16u) | (bits >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+ return float(bits) * 2.3283064365386963e-10; // / 0x100000000
+}
+
+vec2 Hammersley(uint i, uint N) {
+ return vec2(float(i) / float(N), radicalInverse_VdC(i));
+}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl
new file mode 100644
index 0000000000..2570308816
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl
@@ -0,0 +1,63 @@
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_roughness_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];
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_roughness_inc.glsl"
+
+layout(location = 0) in vec2 uv_interp;
+
+layout(set = 0, binding = 0) uniform samplerCube source_cube;
+
+layout(location = 0) out vec4 frag_color;
+/* clang-format on */
+
+void main() {
+ vec3 N = texelCoordToVec(uv_interp * 2.0 - 1.0, params.face_id);
+
+ //vec4 color = color_interp;
+
+ if (params.use_direct_write) {
+ frag_color = vec4(texture(source_cube, N).rgb, 1.0);
+ } else {
+ vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
+
+ for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) {
+ vec2 xi = Hammersley(sampleNum, params.sample_count);
+
+ vec3 H = ImportanceSampleGGX(xi, params.roughness, N);
+ vec3 V = N;
+ vec3 L = (2.0 * dot(V, H) * H - V);
+
+ float ndotl = clamp(dot(N, L), 0.0, 1.0);
+
+ if (ndotl > 0.0) {
+ sum.rgb += textureLod(source_cube, L, 0.0).rgb * ndotl;
+ sum.a += ndotl;
+ }
+ }
+ sum /= sum.a;
+
+ frag_color = vec4(sum.rgb, 1.0);
+ }
+}
diff --git a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
index ccaad13311..158096d3c7 100644
--- a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
@@ -1,18 +1,18 @@
struct DecalData {
- mat4 xform; //to decal transform
- vec3 inv_extents;
- float albedo_mix;
- vec4 albedo_rect;
- vec4 normal_rect;
- vec4 orm_rect;
- vec4 emission_rect;
- vec4 modulate;
- float emission_energy;
+ highp mat4 xform; //to decal transform
+ highp vec3 inv_extents;
+ mediump float albedo_mix;
+ highp vec4 albedo_rect;
+ highp vec4 normal_rect;
+ highp vec4 orm_rect;
+ highp vec4 emission_rect;
+ highp vec4 modulate;
+ mediump float emission_energy;
uint mask;
- float upper_fade;
- float lower_fade;
- mat3x4 normal_xform;
- vec3 normal;
- float normal_fade;
+ mediump float upper_fade;
+ mediump float lower_fade;
+ mediump mat3x4 normal_xform;
+ mediump vec3 normal;
+ mediump float normal_fade;
};
diff --git a/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl b/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl
new file mode 100644
index 0000000000..4e2ba84033
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl
@@ -0,0 +1,173 @@
+/*************************************************************************/
+/* fsr_upscale.glsl */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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. */
+/*************************************************************************/
+
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+#define A_GPU
+#define A_GLSL
+
+#ifdef MODE_FSR_UPSCALE_NORMAL
+
+#define A_HALF
+
+#endif
+
+#include "thirdparty/amd-fsr/ffx_a.h"
+
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+
+layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2D fsr_image;
+layout(set = 0, binding = 0) uniform sampler2D source_image;
+
+#define FSR_UPSCALE_PASS_TYPE_EASU 0
+#define FSR_UPSCALE_PASS_TYPE_RCAS 1
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ float resolution_width;
+ float resolution_height;
+ float upscaled_width;
+ float upscaled_height;
+ float sharpness;
+ int pass;
+}
+params;
+
+AU4 Const0, Const1, Const2, Const3;
+
+#ifdef MODE_FSR_UPSCALE_FALLBACK
+
+#define FSR_EASU_F
+AF4 FsrEasuRF(AF2 p) {
+ AF4 res = textureGather(source_image, p, 0);
+ return res;
+}
+AF4 FsrEasuGF(AF2 p) {
+ AF4 res = textureGather(source_image, p, 1);
+ return res;
+}
+AF4 FsrEasuBF(AF2 p) {
+ AF4 res = textureGather(source_image, p, 2);
+ return res;
+}
+
+#define FSR_RCAS_F
+AF4 FsrRcasLoadF(ASU2 p) {
+ return AF4(texelFetch(source_image, ASU2(p), 0));
+}
+void FsrRcasInputF(inout AF1 r, inout AF1 g, inout AF1 b) {}
+
+#else
+
+#define FSR_EASU_H
+AH4 FsrEasuRH(AF2 p) {
+ AH4 res = AH4(textureGather(source_image, p, 0));
+ return res;
+}
+AH4 FsrEasuGH(AF2 p) {
+ AH4 res = AH4(textureGather(source_image, p, 1));
+ return res;
+}
+AH4 FsrEasuBH(AF2 p) {
+ AH4 res = AH4(textureGather(source_image, p, 2));
+ return res;
+}
+
+#define FSR_RCAS_H
+AH4 FsrRcasLoadH(ASW2 p) {
+ return AH4(texelFetch(source_image, ASU2(p), 0));
+}
+void FsrRcasInputH(inout AH1 r, inout AH1 g, inout AH1 b) {}
+
+#endif
+
+#include "thirdparty/amd-fsr/ffx_fsr1.h"
+
+void fsr_easu_pass(AU2 pos) {
+#ifdef MODE_FSR_UPSCALE_NORMAL
+
+ AH3 Gamma2Color = AH3(0, 0, 0);
+ FsrEasuH(Gamma2Color, pos, Const0, Const1, Const2, Const3);
+ imageStore(fsr_image, ASU2(pos), AH4(Gamma2Color, 1));
+
+#else
+
+ AF3 Gamma2Color = AF3(0, 0, 0);
+ FsrEasuF(Gamma2Color, pos, Const0, Const1, Const2, Const3);
+ imageStore(fsr_image, ASU2(pos), AF4(Gamma2Color, 1));
+
+#endif
+}
+
+void fsr_rcas_pass(AU2 pos) {
+#ifdef MODE_FSR_UPSCALE_NORMAL
+
+ AH3 Gamma2Color = AH3(0, 0, 0);
+ FsrRcasH(Gamma2Color.r, Gamma2Color.g, Gamma2Color.b, pos, Const0);
+ imageStore(fsr_image, ASU2(pos), AH4(Gamma2Color, 1));
+
+#else
+
+ AF3 Gamma2Color = AF3(0, 0, 0);
+ FsrRcasF(Gamma2Color.r, Gamma2Color.g, Gamma2Color.b, pos, Const0);
+ imageStore(fsr_image, ASU2(pos), AF4(Gamma2Color, 1));
+
+#endif
+}
+
+void fsr_pass(AU2 pos) {
+ if (params.pass == FSR_UPSCALE_PASS_TYPE_EASU) {
+ fsr_easu_pass(pos);
+ } else if (params.pass == FSR_UPSCALE_PASS_TYPE_RCAS) {
+ fsr_rcas_pass(pos);
+ }
+}
+
+void main() {
+ // Clang does not like unused functions. If ffx_a.h is included in the binary, clang will throw a fit and not compile so we must configure FSR in this shader
+ if (params.pass == FSR_UPSCALE_PASS_TYPE_EASU) {
+ FsrEasuCon(Const0, Const1, Const2, Const3, params.resolution_width, params.resolution_height, params.resolution_width, params.resolution_height, params.upscaled_width, params.upscaled_height);
+ } else if (params.pass == FSR_UPSCALE_PASS_TYPE_RCAS) {
+ FsrRcasCon(Const0, params.sharpness);
+ }
+
+ AU2 gxy = ARmp8x8(gl_LocalInvocationID.x) + AU2(gl_WorkGroupID.x << 4u, gl_WorkGroupID.y << 4u);
+
+ fsr_pass(gxy);
+ gxy.x += 8u;
+ fsr_pass(gxy);
+ gxy.y += 8u;
+ fsr_pass(gxy);
+ gxy.x -= 8u;
+ fsr_pass(gxy);
+}
diff --git a/servers/rendering/renderer_rd/shaders/gi.glsl b/servers/rendering/renderer_rd/shaders/gi.glsl
index bfd5c4c88d..5528ea3659 100644
--- a/servers/rendering/renderer_rd/shaders/gi.glsl
+++ b/servers/rendering/renderer_rd/shaders/gi.glsl
@@ -35,7 +35,7 @@ layout(set = 0, binding = 11) uniform texture2DArray lightprobe_texture;
layout(set = 0, binding = 12) uniform texture2D depth_buffer;
layout(set = 0, binding = 13) uniform texture2D normal_roughness_buffer;
-layout(set = 0, binding = 14) uniform utexture2D giprobe_buffer;
+layout(set = 0, binding = 14) uniform utexture2D voxel_gi_buffer;
layout(set = 0, binding = 15, std140) uniform SDFGI {
vec3 grid_size;
@@ -65,9 +65,9 @@ layout(set = 0, binding = 15, std140) uniform SDFGI {
}
sdfgi;
-#define MAX_GI_PROBES 8
+#define MAX_VOXEL_GI_INSTANCES 8
-struct GIProbeData {
+struct VoxelGIData {
mat4 xform;
vec3 bounds;
float dynamic_range;
@@ -77,18 +77,18 @@ struct GIProbeData {
bool blend_ambient;
uint texture_slot;
- float anisotropy_strength;
- float ambient_occlusion;
- float ambient_occlusion_size;
+ uint pad0;
+ uint pad1;
+ uint pad2;
uint mipmaps;
};
-layout(set = 0, binding = 16, std140) uniform GIProbes {
- GIProbeData data[MAX_GI_PROBES];
+layout(set = 0, binding = 16, std140) uniform VoxelGIs {
+ VoxelGIData data[MAX_VOXEL_GI_INSTANCES];
}
-gi_probes;
+voxel_gi_instances;
-layout(set = 0, binding = 17) uniform texture3D gi_probe_textures[MAX_GI_PROBES];
+layout(set = 0, binding = 17) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
layout(push_constant, binding = 0, std430) uniform Params {
ivec2 screen_size;
@@ -97,12 +97,10 @@ layout(push_constant, binding = 0, std430) uniform Params {
vec4 proj_info;
- vec3 ao_color;
- uint max_giprobes;
-
+ uint max_voxel_gi_instances;
bool high_quality_vct;
bool orthogonal;
- uint pad[2];
+ uint pad;
mat3x4 cam_rotation;
}
@@ -155,7 +153,7 @@ vec3 reconstruct_position(ivec2 screen_pos) {
return pos;
}
-void sdfgi_probe_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, float roughness, out vec3 diffuse_light, out vec3 specular_light) {
+void sdfvoxel_gi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, float roughness, out vec3 diffuse_light, out vec3 specular_light) {
cascade_pos += cam_normal * sdfgi.normal_bias;
vec3 base_pos = floor(cascade_pos);
@@ -293,7 +291,7 @@ void sdfgi_process(vec3 vertex, vec3 normal, vec3 reflection, float roughness, o
float blend;
vec3 diffuse, specular;
- sdfgi_probe_process(cascade, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse, specular);
+ sdfvoxel_gi_process(cascade, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse, specular);
{
//process blend
@@ -323,7 +321,7 @@ void sdfgi_process(vec3 vertex, vec3 normal, vec3 reflection, float roughness, o
} else {
vec3 diffuse2, specular2;
cascade_pos = (cam_pos - sdfgi.cascades[cascade + 1].position) * sdfgi.cascades[cascade + 1].to_probe;
- sdfgi_probe_process(cascade + 1, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse2, specular2);
+ sdfvoxel_gi_process(cascade + 1, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse2, specular2);
diffuse = mix(diffuse, diffuse2, blend);
specular = mix(specular, specular2, blend);
}
@@ -494,26 +492,26 @@ vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3
return color;
}
-void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, inout vec4 out_spec, inout vec4 out_diff, inout float out_blend) {
- position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz;
- ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz);
- normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz);
+void voxel_gi_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, inout vec4 out_spec, inout vec4 out_diff, inout float out_blend) {
+ position = (voxel_gi_instances.data[index].xform * vec4(position, 1.0)).xyz;
+ ref_vec = normalize((voxel_gi_instances.data[index].xform * vec4(ref_vec, 0.0)).xyz);
+ normal = normalize((voxel_gi_instances.data[index].xform * vec4(normal, 0.0)).xyz);
- position += normal * gi_probes.data[index].normal_bias;
+ position += normal * voxel_gi_instances.data[index].normal_bias;
//this causes corrupted pixels, i have no idea why..
- if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) {
+ if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, voxel_gi_instances.data[index].bounds))))) {
return;
}
- mat3 dir_xform = mat3(gi_probes.data[index].xform) * normal_xform;
+ mat3 dir_xform = mat3(voxel_gi_instances.data[index].xform) * normal_xform;
- vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0);
+ vec3 blendv = abs(position / voxel_gi_instances.data[index].bounds * 2.0 - 1.0);
float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0);
//float blend=1.0;
- float max_distance = length(gi_probes.data[index].bounds);
- vec3 cell_size = 1.0 / gi_probes.data[index].bounds;
+ float max_distance = length(voxel_gi_instances.data[index].bounds);
+ vec3 cell_size = 1.0 / voxel_gi_instances.data[index].bounds;
//irradiance
@@ -534,7 +532,7 @@ void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3
for (uint i = 0; i < cone_dir_count; i++) {
vec3 dir = normalize(dir_xform * cone_dirs[i]);
- light += cone_weights[i] * voxel_cone_trace(gi_probe_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+ light += cone_weights[i] * voxel_cone_trace(voxel_gi_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, voxel_gi_instances.data[index].bias);
}
} else {
const uint cone_dir_count = 4;
@@ -547,42 +545,21 @@ void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3
float cone_weights[cone_dir_count] = float[](0.25, 0.25, 0.25, 0.25);
for (int i = 0; i < cone_dir_count; i++) {
vec3 dir = normalize(dir_xform * cone_dirs[i]);
- light += cone_weights[i] * voxel_cone_trace_45_degrees(gi_probe_textures[index], cell_size, position, dir, max_distance, gi_probes.data[index].bias);
- }
- }
-
- if (gi_probes.data[index].ambient_occlusion > 0.001) {
- float size = 1.0 + gi_probes.data[index].ambient_occlusion_size * 7.0;
-
- float taps, blend;
- blend = modf(size, taps);
- float ao = 0.0;
- for (float i = 1.0; i <= taps; i++) {
- vec3 ofs = (position + normal * (i * 0.5 + 1.0)) * cell_size;
- ao += textureLod(sampler3D(gi_probe_textures[index], linear_sampler_with_mipmaps), ofs, i - 1.0).a * i;
+ light += cone_weights[i] * voxel_cone_trace_45_degrees(voxel_gi_textures[index], cell_size, position, dir, max_distance, voxel_gi_instances.data[index].bias);
}
-
- if (blend > 0.001) {
- vec3 ofs = (position + normal * ((taps + 1.0) * 0.5 + 1.0)) * cell_size;
- ao += textureLod(sampler3D(gi_probe_textures[index], linear_sampler_with_mipmaps), ofs, taps).a * (taps + 1.0) * blend;
- }
-
- ao = 1.0 - min(1.0, ao);
-
- light.rgb = mix(params.ao_color, light.rgb, mix(1.0, ao, gi_probes.data[index].ambient_occlusion));
}
- light.rgb *= gi_probes.data[index].dynamic_range;
- if (!gi_probes.data[index].blend_ambient) {
+ light.rgb *= voxel_gi_instances.data[index].dynamic_range;
+ if (!voxel_gi_instances.data[index].blend_ambient) {
light.a = 1.0;
}
out_diff += light * blend;
//radiance
- vec4 irr_light = voxel_cone_trace(gi_probe_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias);
- irr_light.rgb *= gi_probes.data[index].dynamic_range;
- if (!gi_probes.data[index].blend_ambient) {
+ vec4 irr_light = voxel_cone_trace(voxel_gi_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, voxel_gi_instances.data[index].bias);
+ irr_light.rgb *= voxel_gi_instances.data[index].dynamic_range;
+ if (!voxel_gi_instances.data[index].blend_ambient) {
irr_light.a = 1.0;
}
@@ -614,9 +591,9 @@ void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 ref
sdfgi_process(vertex, normal, reflection, roughness, ambient_light, reflection_light);
#endif
-#ifdef USE_GIPROBES
+#ifdef USE_VOXEL_GI_INSTANCES
{
- uvec2 giprobe_tex = texelFetch(usampler2D(giprobe_buffer, linear_sampler), pos, 0).rg;
+ uvec2 voxel_gi_tex = texelFetch(usampler2D(voxel_gi_buffer, linear_sampler), pos, 0).rg;
roughness *= roughness;
//find arbitrary tangent and bitangent, then build a matrix
vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
@@ -628,9 +605,9 @@ void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 ref
vec4 spec_accum = vec4(0.0);
float blend_accum = 0.0;
- for (uint i = 0; i < params.max_giprobes; i++) {
- if (any(equal(uvec2(i), giprobe_tex))) {
- gi_probe_compute(i, vertex, normal, reflection, normal_mat, roughness, spec_accum, amb_accum, blend_accum);
+ for (uint i = 0; i < params.max_voxel_gi_instances; i++) {
+ if (any(equal(uvec2(i), voxel_gi_tex))) {
+ voxel_gi_compute(i, vertex, normal, reflection, normal_mat, roughness, spec_accum, amb_accum, blend_accum);
}
}
if (blend_accum > 0.0) {
diff --git a/servers/rendering/renderer_rd/shaders/giprobe_write.glsl b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl
index 5dc2d08a3b..25d87ca45d 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe_write.glsl
+++ b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl
@@ -202,12 +202,7 @@ void main() {
vec3 emission = vec3(ivec3(cell_data.data[cell_index].emission & 0x3FF, (cell_data.data[cell_index].emission >> 10) & 0x7FF, cell_data.data[cell_index].emission >> 21)) * params.emission_scale;
vec4 normal = unpackSnorm4x8(cell_data.data[cell_index].normal);
-#ifdef MODE_ANISOTROPIC
- vec3 accum[6] = vec3[](vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
- const vec3 accum_dirs[6] = vec3[](vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0));
-#else
vec3 accum = vec3(0.0);
-#endif
for (uint i = 0; i < params.light_count; i++) {
float attenuation;
@@ -242,77 +237,35 @@ void main() {
vec3 light = lights.data[i].color * albedo.rgb * attenuation * lights.data[i].energy;
-#ifdef MODE_ANISOTROPIC
- for (uint j = 0; j < 6; j++) {
- accum[j] += max(0.0, dot(accum_dir, -light_dir)) * light + emission;
- }
-#else
if (length(normal.xyz) > 0.2) {
accum += max(0.0, dot(normal.xyz, -light_dir)) * light + emission;
} else {
//all directions
accum += light + emission;
}
-#endif
}
-#ifdef MODE_ANISOTROPIC
-
- output.data[cell_index * 6 + 0] = vec4(accum[0], 0.0);
- output.data[cell_index * 6 + 1] = vec4(accum[1], 0.0);
- output.data[cell_index * 6 + 2] = vec4(accum[2], 0.0);
- output.data[cell_index * 6 + 3] = vec4(accum[3], 0.0);
- output.data[cell_index * 6 + 4] = vec4(accum[4], 0.0);
- output.data[cell_index * 6 + 5] = vec4(accum[5], 0.0);
-#else
output.data[cell_index] = vec4(accum, 0.0);
-#endif
-
#endif //MODE_COMPUTE_LIGHT
#ifdef MODE_UPDATE_MIPMAPS
{
-#ifdef MODE_ANISOTROPIC
- vec3 light_accum[6] = vec3[](vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
-#else
vec3 light_accum = vec3(0.0);
-#endif
float count = 0.0;
for (uint i = 0; i < 8; i++) {
uint child_index = cell_children.data[cell_index].children[i];
if (child_index == NO_CHILDREN) {
continue;
}
-#ifdef MODE_ANISOTROPIC
- light_accum[1] += output.data[child_index * 6 + 0].rgb;
- light_accum[2] += output.data[child_index * 6 + 1].rgb;
- light_accum[3] += output.data[child_index * 6 + 2].rgb;
- light_accum[4] += output.data[child_index * 6 + 3].rgb;
- light_accum[5] += output.data[child_index * 6 + 4].rgb;
- light_accum[6] += output.data[child_index * 6 + 5].rgb;
-
-#else
light_accum += output.data[child_index].rgb;
-#endif
-
count += 1.0;
}
float divisor = mix(8.0, count, params.propagation);
-#ifdef MODE_ANISOTROPIC
- output.data[cell_index * 6 + 0] = vec4(light_accum[0] / divisor, 0.0);
- output.data[cell_index * 6 + 1] = vec4(light_accum[1] / divisor, 0.0);
- output.data[cell_index * 6 + 2] = vec4(light_accum[2] / divisor, 0.0);
- output.data[cell_index * 6 + 3] = vec4(light_accum[3] / divisor, 0.0);
- output.data[cell_index * 6 + 4] = vec4(light_accum[4] / divisor, 0.0);
- output.data[cell_index * 6 + 5] = vec4(light_accum[5] / divisor, 0.0);
-
-#else
output.data[cell_index] = vec4(light_accum / divisor, 0.0);
-#endif
}
#endif
diff --git a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
index 2fce258cff..fdc7729338 100644
--- a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
@@ -3,31 +3,31 @@
#define LIGHT_BAKE_STATIC 2
struct LightData { //this structure needs to be as packed as possible
- vec3 position;
- float inv_radius;
+ highp vec3 position;
+ highp float inv_radius;
- vec3 direction;
- float size;
+ mediump vec3 direction;
+ highp float size;
- vec3 color;
- float attenuation;
+ mediump vec3 color;
+ mediump float attenuation;
- float cone_attenuation;
- float cone_angle;
- float specular_amount;
+ mediump float cone_attenuation;
+ mediump float cone_angle;
+ mediump float specular_amount;
bool shadow_enabled;
- vec4 atlas_rect; // rect in the shadow atlas
- mat4 shadow_matrix;
- float shadow_bias;
- float shadow_normal_bias;
- float transmittance_bias;
- float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
- float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
+ highp vec4 atlas_rect; // rect in the shadow atlas
+ highp mat4 shadow_matrix;
+ highp float shadow_bias;
+ highp float shadow_normal_bias;
+ highp float transmittance_bias;
+ highp float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
+ highp float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
uint mask;
- float shadow_volumetric_fog_fade;
+ mediump float shadow_volumetric_fog_fade;
uint bake_mode;
- vec4 projector_rect; //projector rect in srgb decal atlas
+ highp vec4 projector_rect; //projector rect in srgb decal atlas
};
#define REFLECTION_AMBIENT_DISABLED 0
@@ -35,53 +35,53 @@ struct LightData { //this structure needs to be as packed as possible
#define REFLECTION_AMBIENT_COLOR 2
struct ReflectionData {
- vec3 box_extents;
- float index;
- vec3 box_offset;
+ highp vec3 box_extents;
+ mediump float index;
+ highp vec3 box_offset;
uint mask;
- vec3 ambient; // ambient color
- float intensity;
+ mediump vec3 ambient; // ambient color
+ mediump float intensity;
bool exterior;
bool box_project;
uint ambient_mode;
uint pad;
//0-8 is intensity,8-9 is ambient, mode
- mat4 local_matrix; // up to here for spot and omni, rest is for directional
+ highp mat4 local_matrix; // up to here for spot and omni, rest is for directional
// notes: for ambientblend, use distance to edge to blend between already existing global environment
};
struct DirectionalLightData {
- vec3 direction;
- float energy;
- vec3 color;
- float size;
- float specular;
+ mediump vec3 direction;
+ mediump float energy;
+ mediump vec3 color;
+ mediump float size;
+ mediump float specular;
uint mask;
- float softshadow_angle;
- float soft_shadow_scale;
+ highp float softshadow_angle;
+ highp float soft_shadow_scale;
bool blend_splits;
bool shadow_enabled;
- float fade_from;
- float fade_to;
+ highp float fade_from;
+ highp float fade_to;
uvec2 pad;
uint bake_mode;
- float shadow_volumetric_fog_fade;
- vec4 shadow_bias;
- vec4 shadow_normal_bias;
- vec4 shadow_transmittance_bias;
- vec4 shadow_z_range;
- vec4 shadow_range_begin;
- vec4 shadow_split_offsets;
- mat4 shadow_matrix1;
- mat4 shadow_matrix2;
- mat4 shadow_matrix3;
- mat4 shadow_matrix4;
- vec4 shadow_color1;
- vec4 shadow_color2;
- vec4 shadow_color3;
- vec4 shadow_color4;
- vec2 uv_scale1;
- vec2 uv_scale2;
- vec2 uv_scale3;
- vec2 uv_scale4;
+ mediump float shadow_volumetric_fog_fade;
+ highp vec4 shadow_bias;
+ highp vec4 shadow_normal_bias;
+ highp vec4 shadow_transmittance_bias;
+ highp vec4 shadow_z_range;
+ highp vec4 shadow_range_begin;
+ highp vec4 shadow_split_offsets;
+ highp mat4 shadow_matrix1;
+ highp mat4 shadow_matrix2;
+ highp mat4 shadow_matrix3;
+ highp mat4 shadow_matrix4;
+ mediump vec4 shadow_color1;
+ mediump vec4 shadow_color2;
+ mediump vec4 shadow_color3;
+ mediump vec4 shadow_color4;
+ highp vec2 uv_scale1;
+ highp vec2 uv_scale2;
+ highp vec2 uv_scale3;
+ highp vec2 uv_scale4;
};
diff --git a/servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl
new file mode 100644
index 0000000000..29ebd74a90
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl
@@ -0,0 +1,74 @@
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "luminance_reduce_raster_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];
+
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "luminance_reduce_raster_inc.glsl"
+
+layout(location = 0) in vec2 uv_interp;
+/* clang-format on */
+
+layout(set = 0, binding = 0) uniform sampler2D source_exposure;
+
+#ifdef FINAL_PASS
+layout(set = 1, binding = 0) uniform sampler2D prev_luminance;
+#endif
+
+layout(location = 0) out highp float luminance;
+
+void main() {
+ ivec2 dest_pos = ivec2(uv_interp * settings.dest_size);
+ ivec2 src_pos = ivec2(uv_interp * settings.source_size);
+
+ ivec2 next_pos = (dest_pos + ivec2(1)) * settings.source_size / settings.dest_size;
+ next_pos = max(next_pos, src_pos + ivec2(1)); //so it at least reads one pixel
+
+ highp vec3 source_color = vec3(0.0);
+ for (int i = src_pos.x; i < next_pos.x; i++) {
+ for (int j = src_pos.y; j < next_pos.y; j++) {
+ source_color += texelFetch(source_exposure, ivec2(i, j), 0).rgb;
+ }
+ }
+
+ source_color /= float((next_pos.x - src_pos.x) * (next_pos.y - src_pos.y));
+
+#ifdef FIRST_PASS
+ luminance = max(source_color.r, max(source_color.g, source_color.b));
+
+ // This formula should be more "accurate" but gave an overexposed result when testing.
+ // Leaving it here so we can revisit it if we want.
+ // luminance = source_color.r * 0.21 + source_color.g * 0.71 + source_color.b * 0.07;
+#else
+ luminance = source_color.r;
+#endif
+
+#ifdef FINAL_PASS
+ // Obtain our target luminance
+ luminance = clamp(luminance, settings.min_luminance, settings.max_luminance);
+
+ // Now smooth to our transition
+ highp float prev_lum = texelFetch(prev_luminance, ivec2(0, 0), 0).r; //1 pixel previous luminance
+ luminance = prev_lum + (luminance - prev_lum) * clamp(settings.exposure_adjust, 0.0, 1.0);
+#endif
+}
diff --git a/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl
new file mode 100644
index 0000000000..3cde9923fa
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl
@@ -0,0 +1,11 @@
+
+layout(push_constant, binding = 1, std430) uniform PushConstant {
+ ivec2 source_size;
+ ivec2 dest_size;
+
+ float exposure_adjust;
+ float min_luminance;
+ float max_luminance;
+ uint pad1;
+}
+settings;
diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl
index beaff10793..328becbc20 100644
--- a/servers/rendering/renderer_rd/shaders/particles.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles.glsl
@@ -19,6 +19,8 @@ layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
+#define SDF_MAX_LENGTH 16384.0
+
/* SET 0: GLOBAL DATA */
layout(set = 0, binding = 1) uniform sampler material_samplers[12];
@@ -54,6 +56,7 @@ struct Attractor {
#define COLLIDER_TYPE_BOX 1
#define COLLIDER_TYPE_SDF 2
#define COLLIDER_TYPE_HEIGHT_FIELD 3
+#define COLLIDER_TYPE_2D_SDF 4
struct Collider {
mat4 transform;
@@ -452,128 +455,167 @@ void main() {
#endif
- for (uint i = 0; i < FRAME.collider_count; i++) {
- vec3 normal;
- float depth;
- bool col = false;
+ if (FRAME.collider_count == 1 && FRAME.colliders[0].type == COLLIDER_TYPE_2D_SDF) {
+ //2D collision
- vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz;
- vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform);
+ vec2 pos = PARTICLE.xform[3].xy;
+ vec4 to_sdf_x = FRAME.colliders[0].transform[0];
+ vec4 to_sdf_y = FRAME.colliders[0].transform[1];
+ vec2 sdf_pos = vec2(dot(vec4(pos, 0, 1), to_sdf_x), dot(vec4(pos, 0, 1), to_sdf_y));
- switch (FRAME.colliders[i].type) {
- case COLLIDER_TYPE_SPHERE: {
- float d = length(rel_vec) - (particle_size + FRAME.colliders[i].extents.x);
+ vec4 sdf_to_screen = vec4(FRAME.colliders[0].extents, FRAME.colliders[0].scale);
- if (d < 0.0) {
- col = true;
- depth = -d;
- normal = normalize(rel_vec);
- }
+ vec2 uv_pos = sdf_pos * sdf_to_screen.xy + sdf_to_screen.zw;
- } break;
- case COLLIDER_TYPE_BOX: {
- vec3 abs_pos = abs(local_pos);
- vec3 sgn_pos = sign(local_pos);
+ if (all(greaterThan(uv_pos, vec2(0.0))) && all(lessThan(uv_pos, vec2(1.0)))) {
+ vec2 pos2 = pos + vec2(0, particle_size);
+ vec2 sdf_pos2 = vec2(dot(vec4(pos2, 0, 1), to_sdf_x), dot(vec4(pos2, 0, 1), to_sdf_y));
+ float sdf_particle_size = distance(sdf_pos, sdf_pos2);
+
+ float d = texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos).r * SDF_MAX_LENGTH;
+
+ d -= sdf_particle_size;
+
+ if (d < 0.0) {
+ const float EPSILON = 0.001;
+ vec2 n = normalize(vec2(
+ texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos + vec2(EPSILON, 0.0)).r - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos - vec2(EPSILON, 0.0)).r,
+ texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos + vec2(0.0, EPSILON)).r - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos - vec2(0.0, EPSILON)).r));
+
+ collided = true;
+ sdf_pos2 = sdf_pos + n * d;
+ pos2 = vec2(dot(vec4(sdf_pos2, 0, 1), FRAME.colliders[0].transform[2]), dot(vec4(sdf_pos2, 0, 1), FRAME.colliders[0].transform[3]));
+
+ n = pos - pos2;
+
+ collision_normal = normalize(vec3(n, 0.0));
+ collision_depth = length(n);
+ }
+ }
+
+ } else {
+ for (uint i = 0; i < FRAME.collider_count; i++) {
+ vec3 normal;
+ float depth;
+ bool col = false;
- if (any(greaterThan(abs_pos, FRAME.colliders[i].extents))) {
- //point outside box
+ vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz;
+ vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform);
- vec3 closest = min(abs_pos, FRAME.colliders[i].extents);
- vec3 rel = abs_pos - closest;
- depth = length(rel) - particle_size;
- if (depth < 0.0) {
+ switch (FRAME.colliders[i].type) {
+ case COLLIDER_TYPE_SPHERE: {
+ float d = length(rel_vec) - (particle_size + FRAME.colliders[i].extents.x);
+
+ if (d < 0.0) {
col = true;
- normal = mat3(FRAME.colliders[i].transform) * (normalize(rel) * sgn_pos);
- depth = -depth;
+ depth = -d;
+ normal = normalize(rel_vec);
}
- } else {
- //point inside box
- vec3 axis_len = FRAME.colliders[i].extents - abs_pos;
- // there has to be a faster way to do this?
- if (all(lessThan(axis_len.xx, axis_len.yz))) {
- normal = vec3(1, 0, 0);
- } else if (all(lessThan(axis_len.yy, axis_len.xz))) {
- normal = vec3(0, 1, 0);
+
+ } break;
+ case COLLIDER_TYPE_BOX: {
+ vec3 abs_pos = abs(local_pos);
+ vec3 sgn_pos = sign(local_pos);
+
+ if (any(greaterThan(abs_pos, FRAME.colliders[i].extents))) {
+ //point outside box
+
+ vec3 closest = min(abs_pos, FRAME.colliders[i].extents);
+ vec3 rel = abs_pos - closest;
+ depth = length(rel) - particle_size;
+ if (depth < 0.0) {
+ col = true;
+ normal = mat3(FRAME.colliders[i].transform) * (normalize(rel) * sgn_pos);
+ depth = -depth;
+ }
} else {
- normal = vec3(0, 0, 1);
+ //point inside box
+ vec3 axis_len = FRAME.colliders[i].extents - abs_pos;
+ // there has to be a faster way to do this?
+ if (all(lessThan(axis_len.xx, axis_len.yz))) {
+ normal = vec3(1, 0, 0);
+ } else if (all(lessThan(axis_len.yy, axis_len.xz))) {
+ normal = vec3(0, 1, 0);
+ } else {
+ normal = vec3(0, 0, 1);
+ }
+
+ col = true;
+ depth = dot(normal * axis_len, vec3(1)) + particle_size;
+ normal = mat3(FRAME.colliders[i].transform) * (normal * sgn_pos);
}
- col = true;
- depth = dot(normal * axis_len, vec3(1)) + particle_size;
- normal = mat3(FRAME.colliders[i].transform) * (normal * sgn_pos);
- }
+ } break;
+ case COLLIDER_TYPE_SDF: {
+ vec3 apos = abs(local_pos);
+ float extra_dist = 0.0;
+ if (any(greaterThan(apos, FRAME.colliders[i].extents))) { //outside
+ vec3 mpos = min(apos, FRAME.colliders[i].extents);
+ extra_dist = distance(mpos, apos);
+ }
- } break;
- case COLLIDER_TYPE_SDF: {
- vec3 apos = abs(local_pos);
- float extra_dist = 0.0;
- if (any(greaterThan(apos, FRAME.colliders[i].extents))) { //outside
- vec3 mpos = min(apos, FRAME.colliders[i].extents);
- extra_dist = distance(mpos, apos);
- }
+ if (extra_dist > particle_size) {
+ continue;
+ }
- if (extra_dist > particle_size) {
- continue;
- }
+ vec3 uvw_pos = (local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5;
+ float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).r;
+ s *= FRAME.colliders[i].scale;
+ s += extra_dist;
+ if (s < particle_size) {
+ col = true;
+ depth = particle_size - s;
+ const float EPSILON = 0.001;
+ normal = mat3(FRAME.colliders[i].transform) *
+ normalize(
+ vec3(
+ texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r,
+ texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r,
+ texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r));
+ }
- vec3 uvw_pos = (local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5;
- float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).r;
- s *= FRAME.colliders[i].scale;
- s += extra_dist;
- if (s < particle_size) {
- col = true;
- depth = particle_size - s;
- const float EPSILON = 0.001;
- normal = mat3(FRAME.colliders[i].transform) *
- normalize(
- vec3(
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r,
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r,
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r));
- }
+ } break;
+ case COLLIDER_TYPE_HEIGHT_FIELD: {
+ vec3 local_pos_bottom = local_pos;
+ local_pos_bottom.y -= particle_size;
- } break;
- case COLLIDER_TYPE_HEIGHT_FIELD: {
- vec3 local_pos_bottom = local_pos;
- local_pos_bottom.y -= particle_size;
+ if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) {
+ continue;
+ }
+ const float DELTA = 1.0 / 8192.0;
- if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) {
- continue;
- }
+ vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5;
- const float DELTA = 1.0 / 8192.0;
+ float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r;
- vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5;
+ if (y > uvw_pos.y) {
+ //inside heightfield
- float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r;
+ vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
+ vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
+ vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents;
- if (y > uvw_pos.y) {
- //inside heightfield
+ normal = normalize(cross(pos1 - pos2, pos1 - pos3));
+ float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y;
- vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
- vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
- vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents;
+ col = true;
+ depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
+ }
- normal = normalize(cross(pos1 - pos2, pos1 - pos3));
- float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y;
+ } break;
+ }
- col = true;
- depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
+ if (col) {
+ if (!collided) {
+ collided = true;
+ collision_normal = normal;
+ collision_depth = depth;
+ } else {
+ vec3 c = collision_normal * collision_depth;
+ c += normal * max(0.0, depth - dot(normal, c));
+ collision_normal = normalize(c);
+ collision_depth = length(c);
}
-
- } break;
- }
-
- if (col) {
- if (!collided) {
- collided = true;
- collision_normal = normal;
- collision_depth = depth;
- } else {
- vec3 c = collision_normal * collision_depth;
- c += normal * max(0.0, depth - dot(normal, c));
- collision_normal = normalize(c);
- collision_depth = length(c);
}
}
}
diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
index e2bebadf1a..e88e68b511 100644
--- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
@@ -53,6 +53,11 @@ layout(push_constant, binding = 0, std430) uniform Params {
vec3 align_up;
uint align_mode;
+
+ bool order_by_lifetime;
+ uint lifetime_split;
+ bool lifetime_reverse;
+ uint pad;
}
params;
@@ -80,7 +85,6 @@ void main() {
#ifdef MODE_FILL_INSTANCES
uint particle = gl_GlobalInvocationID.x;
- uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom
if (particle >= params.total_particles) {
return; //discard
@@ -93,14 +97,48 @@ void main() {
} else {
particle = uint(sort_buffer.data[particle].y); //use index from sort buffer
}
-#endif
+#else
+ if (params.order_by_lifetime) {
+ if (params.trail_size > 1) {
+ uint limit = (params.total_particles / params.trail_size) - params.lifetime_split;
+
+ uint base_index = particle / params.trail_size;
+ uint base_offset = particle % params.trail_size;
+
+ if (params.lifetime_reverse) {
+ base_index = (params.total_particles / params.trail_size) - base_index - 1;
+ }
+
+ if (base_index < limit) {
+ base_index = params.lifetime_split + base_index;
+ } else {
+ base_index -= limit;
+ }
+
+ particle = base_index * params.trail_size + base_offset;
+
+ } else {
+ uint limit = params.total_particles - params.lifetime_split;
+
+ if (params.lifetime_reverse) {
+ particle = params.total_particles - particle - 1;
+ }
+
+ if (particle < limit) {
+ particle = params.lifetime_split + particle;
+ } else {
+ particle -= limit;
+ }
+ }
+ }
+#endif // USE_SORT_BUFFER
mat4 txform;
if (bool(particles.data[particle].flags & PARTICLE_FLAG_ACTIVE) || bool(particles.data[particle].flags & PARTICLE_FLAG_TRAILED)) {
txform = particles.data[particle].xform;
if (params.trail_size > 1) {
- // since the steps dont fit precisely in the history frames, must do a tiny bit of
+ // Since the steps don't fit precisely in the history frames, must do a tiny bit of
// interpolation to get them close to their intended location.
uint part_ofs = particle % params.trail_size;
float natural_ofs = fract((float(part_ofs) / float(params.trail_size)) * float(params.trail_total)) * params.frame_delta;
@@ -165,12 +203,17 @@ void main() {
#ifdef MODE_2D
+ uint write_offset = gl_GlobalInvocationID.x * (2 + 1 + 1); //xform + color + custom
+
instances.data[write_offset + 0] = txform[0];
instances.data[write_offset + 1] = txform[1];
instances.data[write_offset + 2] = particles.data[particle].color;
instances.data[write_offset + 3] = particles.data[particle].custom;
#else
+
+ uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom
+
instances.data[write_offset + 0] = txform[0];
instances.data[write_offset + 1] = txform[1];
instances.data[write_offset + 2] = txform[2];
diff --git a/servers/rendering/renderer_rd/shaders/resolve.glsl b/servers/rendering/renderer_rd/shaders/resolve.glsl
index 2286a26485..fecf812a8c 100644
--- a/servers/rendering/renderer_rd/shaders/resolve.glsl
+++ b/servers/rendering/renderer_rd/shaders/resolve.glsl
@@ -6,6 +6,11 @@
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+#ifdef MODE_RESOLVE_DEPTH
+layout(set = 0, binding = 0) uniform sampler2DMS source_depth;
+layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D dest_depth;
+#endif
+
#ifdef MODE_RESOLVE_GI
layout(set = 0, binding = 0) uniform sampler2DMS source_depth;
layout(set = 0, binding = 1) uniform sampler2DMS source_normal_roughness;
@@ -13,9 +18,9 @@ layout(set = 0, binding = 1) uniform sampler2DMS source_normal_roughness;
layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D dest_depth;
layout(rgba8, set = 1, binding = 1) uniform restrict writeonly image2D dest_normal_roughness;
-#ifdef GIPROBE_RESOLVE
-layout(set = 2, binding = 0) uniform usampler2DMS source_giprobe;
-layout(rg8ui, set = 3, binding = 0) uniform restrict writeonly uimage2D dest_giprobe;
+#ifdef VOXEL_GI_RESOLVE
+layout(set = 2, binding = 0) uniform usampler2DMS source_voxel_gi;
+layout(rg8ui, set = 3, binding = 0) uniform restrict writeonly uimage2D dest_voxel_gi;
#endif
#endif
@@ -34,12 +39,23 @@ void main() {
return;
}
+#ifdef MODE_RESOLVE_DEPTH
+
+ float depth_avg = 0.0;
+ for (int i = 0; i < params.sample_count; i++) {
+ depth_avg += texelFetch(source_depth, pos, i).r;
+ }
+ depth_avg /= float(params.sample_count);
+ imageStore(dest_depth, pos, vec4(depth_avg));
+
+#endif
+
#ifdef MODE_RESOLVE_GI
float best_depth = 1e20;
vec4 best_normal_roughness = vec4(0.0);
-#ifdef GIPROBE_RESOLVE
- uvec2 best_giprobe;
+#ifdef VOXEL_GI_RESOLVE
+ uvec2 best_voxel_gi;
#endif
#if 0
@@ -50,8 +66,8 @@ void main() {
best_depth = depth;
best_normal_roughness = texelFetch(source_normal_roughness,pos,i);
-#ifdef GIPROBE_RESOLVE
- best_giprobe = texelFetch(source_giprobe,pos,i).rg;
+#ifdef VOXEL_GI_RESOLVE
+ best_voxel_gi = texelFetch(source_voxel_gi,pos,i).rg;
#endif
}
}
@@ -204,16 +220,16 @@ void main() {
#endif
best_depth = texelFetch(source_depth, pos, best_index).r;
best_normal_roughness = texelFetch(source_normal_roughness, pos, best_index);
-#ifdef GIPROBE_RESOLVE
- best_giprobe = texelFetch(source_giprobe, pos, best_index).rg;
+#ifdef VOXEL_GI_RESOLVE
+ best_voxel_gi = texelFetch(source_voxel_gi, pos, best_index).rg;
#endif
#endif
imageStore(dest_depth, pos, vec4(best_depth));
imageStore(dest_normal_roughness, pos, vec4(best_normal_roughness));
-#ifdef GIPROBE_RESOLVE
- imageStore(dest_giprobe, pos, uvec4(best_giprobe, 0, 0));
+#ifdef VOXEL_GI_RESOLVE
+ imageStore(dest_voxel_gi, pos, uvec4(best_voxel_gi, 0, 0));
#endif
#endif
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl
index 99714b4504..97c913d489 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl
@@ -2,7 +2,7 @@
float hash_2d(vec2 p) {
return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) *
- (0.1 + abs(sin(13.0 * p.y + p.x))));
+ (0.1 + abs(sin(13.0 * p.y + p.x))));
}
float hash_3d(vec3 p) {
@@ -29,8 +29,7 @@ float compute_alpha_hash_threshold(vec3 pos, float hash_scale) {
vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)),
(a_interp - 0.5 * min_lerp) / (1.0 - min_lerp),
- 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) /
- (2.0 * min_lerp * (1.0 - min_lerp))));
+ 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) / (2.0 * min_lerp * (1.0 - min_lerp))));
float alpha_hash_threshold =
(lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
index 1d67a3f1df..e4628b2d5a 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
@@ -6,6 +6,8 @@
#include "scene_forward_clustered_inc.glsl"
+#define SHADER_IS_SRGB false
+
/* INPUT ATTRIBS */
layout(location = 0) in vec3 vertex_attrib;
@@ -95,7 +97,7 @@ layout(location = 8) out float dp_clip;
#endif
-layout(location = 9) out flat uint instance_index;
+layout(location = 9) out flat uint instance_index_interp;
invariant gl_Position;
@@ -107,18 +109,20 @@ void main() {
color_interp = color_attrib;
#endif
- instance_index = draw_call.instance_index;
+ uint instance_index = draw_call.instance_index;
bool is_multimesh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH);
if (!is_multimesh) {
instance_index += gl_InstanceIndex;
}
+ instance_index_interp = instance_index;
+
mat4 world_matrix = instances.data[instance_index].transform;
mat3 world_normal_matrix;
if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
- world_normal_matrix = inverse(mat3(world_matrix));
+ world_normal_matrix = transpose(inverse(mat3(world_matrix)));
} else {
world_normal_matrix = mat3(world_matrix);
}
@@ -356,6 +360,29 @@ void main() {
#VERSION_DEFINES
+#define SHADER_IS_SRGB false
+
+/* Specialization Constants (Toggles) */
+
+layout(constant_id = 0) const bool sc_use_forward_gi = false;
+layout(constant_id = 1) const bool sc_use_light_projector = false;
+layout(constant_id = 2) const bool sc_use_light_soft_shadows = false;
+layout(constant_id = 3) const bool sc_use_directional_soft_shadows = false;
+
+/* Specialization Constants (Values) */
+
+layout(constant_id = 6) const uint sc_soft_shadow_samples = 4;
+layout(constant_id = 7) const uint sc_penumbra_shadow_samples = 4;
+
+layout(constant_id = 8) const uint sc_directional_soft_shadow_samples = 4;
+layout(constant_id = 9) const uint sc_directional_penumbra_shadow_samples = 4;
+
+layout(constant_id = 10) const bool sc_decal_use_mipmaps = true;
+layout(constant_id = 11) const bool sc_projector_use_mipmaps = true;
+
+// not used in clustered renderer but we share some code with the mobile renderer that requires this.
+const float sc_luminance_multiplier = 1.0;
+
#include "scene_forward_clustered_inc.glsl"
/* Varyings */
@@ -389,7 +416,7 @@ layout(location = 8) in float dp_clip;
#endif
-layout(location = 9) in flat uint instance_index;
+layout(location = 9) in flat uint instance_index_interp;
//defines to keep compatibility with vertex
@@ -426,8 +453,8 @@ layout(location = 4) out float depth_output_buffer;
#ifdef MODE_RENDER_NORMAL_ROUGHNESS
layout(location = 0) out vec4 normal_roughness_output_buffer;
-#ifdef MODE_RENDER_GIPROBE
-layout(location = 1) out uvec2 giprobe_buffer;
+#ifdef MODE_RENDER_VOXEL_GI
+layout(location = 1) out uvec2 voxel_gi_buffer;
#endif
#endif //MODE_RENDER_NORMAL
@@ -448,14 +475,15 @@ layout(location = 0) out vec4 frag_color;
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
-#include "scene_forward_lights_inc.glsl"
+/* Make a default specular mode SPECULAR_SCHLICK_GGX. */
+#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) && !defined(SPECULAR_PHONG) && !defined(SPECULAR_TOON)
+#define SPECULAR_SCHLICK_GGX
+#endif
-#ifdef USE_FORWARD_GI
+#include "scene_forward_lights_inc.glsl"
#include "scene_forward_gi_inc.glsl"
-#endif //USE_FORWARD_GI
-
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
#ifndef MODE_RENDER_DEPTH
@@ -502,14 +530,14 @@ vec4 fog_process(vec3 vertex) {
}
}
- float fog_amount = 1.0 - exp(min(0.0, vertex.z * scene_data.fog_density));
+ float fog_amount = 1.0 - exp(min(0.0, -length(vertex) * scene_data.fog_density));
- if (abs(scene_data.fog_height_density) > 0.001) {
+ if (abs(scene_data.fog_height_density) >= 0.0001) {
float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y;
- float y_dist = scene_data.fog_height - y;
+ float y_dist = y - scene_data.fog_height;
- float vfog_amount = clamp(exp(y_dist * scene_data.fog_height_density), 0.0, 1.0);
+ float vfog_amount = 1.0 - exp(min(0.0, y_dist * scene_data.fog_height_density));
fog_amount = max(vfog_amount, fog_amount);
}
@@ -542,14 +570,15 @@ void main() {
discard;
#endif
+ uint instance_index = instance_index_interp;
+
//lay out everything, whathever is unused is optimized away anyway
vec3 vertex = vertex_interp;
vec3 view = -normalize(vertex_interp);
vec3 albedo = vec3(1.0);
vec3 backlight = vec3(0.0);
- vec4 transmittance_color = vec4(0.0);
+ vec4 transmittance_color = vec4(0.0, 0.0, 0.0, 1.0);
float transmittance_depth = 0.0;
- float transmittance_curve = 1.0;
float transmittance_boost = 0.0;
float metallic = 0.0;
float specular = 0.5;
@@ -572,7 +601,7 @@ void main() {
float ao = 1.0;
float ao_light_affect = 0.0;
- float alpha = 1.0;
+ float alpha = float(instances.data[instance_index].flags >> INSTANCE_FLAGS_FADE_SHIFT) / float(255.0);
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
vec3 binormal = normalize(binormal_interp);
@@ -634,12 +663,8 @@ void main() {
}
#ifdef LIGHT_TRANSMITTANCE_USED
-#ifdef SSS_MODE_SKIN
- transmittance_color.a = sss_strength;
-#else
transmittance_color.a *= sss_strength;
#endif
-#endif
#ifndef USE_SHADOW_TO_OPACITY
@@ -662,7 +687,7 @@ void main() {
#endif
#ifdef ALPHA_ANTIALIASING_EDGE_USED
-// If alpha scissor is used, we must further the edge threshold, otherwise we wont get any edge feather
+// If alpha scissor is used, we must further the edge threshold, otherwise we won't get any edge feather
#ifdef ALPHA_SCISSOR_USED
alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0);
#endif
@@ -670,7 +695,7 @@ void main() {
#endif // ALPHA_ANTIALIASING_EDGE_USED
#ifdef USE_OPAQUE_PREPASS
- if (alpha < opaque_prepass_threshold) {
+ if (alpha < scene_data.opaque_prepass_threshold) {
discard;
}
#endif // USE_OPAQUE_PREPASS
@@ -798,25 +823,35 @@ void main() {
continue; //out of decal
}
- //we need ddx/ddy for mipmaps, so simulate them
- vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
- vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
-
float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade);
if (decals.data[decal_index].normal_fade > 0.0) {
fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5);
}
+ //we need ddx/ddy for mipmaps, so simulate them
+ vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
+ vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
+
if (decals.data[decal_index].albedo_rect != vec4(0.0)) {
//has albedo
- vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ vec4 decal_albedo;
+ if (sc_decal_use_mipmaps) {
+ decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ } else {
+ decal_albedo = textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, 0.0);
+ }
decal_albedo *= decals.data[decal_index].modulate;
decal_albedo.a *= fade;
albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix);
if (decals.data[decal_index].normal_rect != vec4(0.0)) {
- vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ vec3 decal_normal;
+ if (sc_decal_use_mipmaps) {
+ decal_normal = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ } else {
+ decal_normal = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, 0.0).xyz;
+ }
decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software
decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy)));
//convert to view space, use xzy because y is up
@@ -826,7 +861,12 @@ void main() {
}
if (decals.data[decal_index].orm_rect != vec4(0.0)) {
- vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+ vec3 decal_orm;
+ if (sc_decal_use_mipmaps) {
+ decal_orm = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+ } else {
+ decal_orm = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, 0.0).xyz;
+ }
ao = mix(ao, decal_orm.r, decal_albedo.a);
roughness = mix(roughness, decal_orm.g, decal_albedo.a);
metallic = mix(metallic, decal_orm.b, decal_albedo.a);
@@ -835,7 +875,11 @@ void main() {
if (decals.data[decal_index].emission_rect != vec4(0.0)) {
//emission is additive, so its independent from albedo
- emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ if (sc_decal_use_mipmaps) {
+ emission += textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ } else {
+ emission += textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, 0.0).xyz * decals.data[decal_index].emission_energy * fade;
+ }
}
}
}
@@ -848,9 +892,9 @@ void main() {
#ifdef NORMAL_USED
if (scene_data.roughness_limiter_enabled) {
- //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
+ //https://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
float roughness2 = roughness * roughness;
- vec3 dndu = dFdx(normal), dndv = dFdx(normal);
+ vec3 dndu = dFdx(normal), dndv = dFdy(normal);
float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv));
float kernelRoughness2 = min(2.0 * variance, scene_data.roughness_limiter_limit); //limit effect
float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2);
@@ -867,6 +911,7 @@ void main() {
if (scene_data.use_reflection_cubemap) {
vec3 ref_vec = reflect(-view, normal);
+ float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
ref_vec = scene_data.radiance_inverse_xform * ref_vec;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
@@ -879,6 +924,7 @@ void main() {
specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
+ specular_light *= horizon * horizon;
specular_light *= scene_data.ambient_light_color_energy.a;
}
@@ -904,7 +950,7 @@ void main() {
}
#endif // USE_LIGHTMAP
#if defined(CUSTOM_IRRADIANCE_USED)
- ambient_light = mix(specular_light, custom_irradiance.rgb, custom_irradiance.a);
+ ambient_light = mix(ambient_light, custom_irradiance.rgb, custom_irradiance.a);
#endif
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
@@ -926,15 +972,15 @@ void main() {
const float c4 = 0.886227;
const float c5 = 0.247708;
ambient_light += (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) +
- c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
- c4 * lightmap_captures.data[index].sh[0].rgb -
- c5 * lightmap_captures.data[index].sh[6].rgb +
- 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y +
- 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z +
- 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z +
- 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x +
- 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y +
- 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z);
+ c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
+ c4 * lightmap_captures.data[index].sh[0].rgb -
+ c5 * lightmap_captures.data[index].sh[6].rgb +
+ 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y +
+ 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z +
+ 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z +
+ 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x +
+ 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y +
+ 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z);
} else if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
bool uses_sh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
@@ -968,9 +1014,9 @@ void main() {
ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw, 0.0).rgb;
}
}
-#elif defined(USE_FORWARD_GI)
+#else
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SDFGI)) { //has lightmap capture
+ if (sc_use_forward_gi && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SDFGI)) { //has lightmap capture
//make vertex orientation the world one, but still align to camera
vec3 cam_pos = mat3(scene_data.camera_matrix) * vertex;
@@ -1042,7 +1088,7 @@ void main() {
}
}
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes
+ if (sc_use_forward_gi && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_VOXEL_GI)) { // process voxel_gi_instances
uint index1 = instances.data[instance_index].gi_offset & 0xFFFF;
vec3 ref_vec = normalize(reflect(normalize(vertex), normal));
@@ -1054,12 +1100,12 @@ void main() {
vec4 amb_accum = vec4(0.0);
vec4 spec_accum = vec4(0.0);
- gi_probe_compute(index1, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum);
+ voxel_gi_compute(index1, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum);
uint index2 = instances.data[instance_index].gi_offset >> 16;
if (index2 != 0xFFFF) {
- gi_probe_compute(index2, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum);
+ voxel_gi_compute(index2, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum);
}
if (amb_accum.a > 0.0) {
@@ -1073,9 +1119,8 @@ void main() {
specular_light = spec_accum.rgb;
ambient_light = amb_accum.rgb;
}
-#else
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers
+ if (!sc_use_forward_gi && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers
vec2 coord;
@@ -1106,7 +1151,7 @@ void main() {
ambient_light = mix(ambient_light, buffer_ambient.rgb, buffer_ambient.a);
specular_light = mix(specular_light, buffer_reflection.rgb, buffer_reflection.a);
}
-#endif
+#endif // !USE_LIGHTMAP
if (scene_data.ssao_enabled) {
float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r;
@@ -1187,7 +1232,7 @@ void main() {
specular_light *= specular * metallic * albedo * 2.0;
#else
- // scales the specular reflections, needs to be be computed before lighting happens,
+ // scales the specular reflections, needs to be computed before lighting happens,
// but after environment, GI, and reflection probes are added
// Environment brdf approximation (Lazarov 2013)
// see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
@@ -1212,9 +1257,10 @@ void main() {
// LIGHTING
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
- { //directional light
+ { // Directional light.
- // Do shadow and lighting in two passes to reduce register pressure
+ // Do shadow and lighting in two passes to reduce register pressure.
+#ifndef SHADOWS_DISABLED
uint shadow0 = 0;
uint shadow1 = 0;
@@ -1233,306 +1279,178 @@ void main() {
float shadow = 1.0;
-#ifdef USE_SOFT_SHADOWS
- //version with soft shadows, more expensive
if (directional_lights.data[i].shadow_enabled) {
float depth_z = -vertex.z;
-
- vec4 pssm_coord;
- vec3 shadow_color = vec3(0.0);
vec3 light_dir = directional_lights.data[i].direction;
+ vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp))));
-#define BIAS_FUNC(m_var, m_idx) \
- m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
- vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))) * directional_lights.data[i].shadow_normal_bias[m_idx]; \
- normal_bias -= light_dir * dot(light_dir, normal_bias); \
+#define BIAS_FUNC(m_var, m_idx) \
+ m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
+ vec3 normal_bias = base_normal_bias * directional_lights.data[i].shadow_normal_bias[m_idx]; \
+ normal_bias -= light_dir * dot(light_dir, normal_bias); \
m_var.xyz += normal_bias;
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
- vec4 v = vec4(vertex, 1.0);
+ //version with soft shadows, more expensive
+ if (sc_use_directional_soft_shadows && directional_lights.data[i].softshadow_angle > 0) {
+ uint blend_count = 0;
+ const uint blend_max = directional_lights.data[i].blend_splits ? 2 : 1;
- BIAS_FUNC(v, 0)
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ vec4 v = vec4(vertex, 1.0);
- pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
- pssm_coord /= pssm_coord.w;
+ BIAS_FUNC(v, 0)
+
+ vec4 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);
+ blend_count++;
}
- shadow_color = directional_lights.data[i].shadow_color1.rgb;
-
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
- vec4 v = vec4(vertex, 1.0);
+ if (blend_count < blend_max && depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 1)
+ BIAS_FUNC(v, 1)
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
- pssm_coord /= pssm_coord.w;
+ vec4 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);
+ float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+
+ if (blend_count == 0) {
+ shadow = s;
+ } else {
+ //blend
+ float blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
+ shadow = mix(shadow, s, blend);
+ }
+
+ blend_count++;
}
- shadow_color = directional_lights.data[i].shadow_color2.rgb;
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
- vec4 v = vec4(vertex, 1.0);
+ if (blend_count < blend_max && depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 2)
+ BIAS_FUNC(v, 2)
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
- pssm_coord /= pssm_coord.w;
+ vec4 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);
- }
+ float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- shadow_color = directional_lights.data[i].shadow_color3.rgb;
+ if (blend_count == 0) {
+ shadow = s;
+ } else {
+ //blend
+ float blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+ shadow = mix(shadow, s, blend);
+ }
- } else {
- vec4 v = vec4(vertex, 1.0);
+ blend_count++;
+ }
- BIAS_FUNC(v, 3)
+ if (blend_count < blend_max) {
+ vec4 v = vec4(vertex, 1.0);
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
- pssm_coord /= pssm_coord.w;
+ BIAS_FUNC(v, 3)
+
+ vec4 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);
- }
+ float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- shadow_color = directional_lights.data[i].shadow_color4.rgb;
- }
+ if (blend_count == 0) {
+ shadow = s;
+ } else {
+ //blend
+ float blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
+ shadow = mix(shadow, s, blend);
+ }
+ }
- if (directional_lights.data[i].blend_splits) {
- vec3 shadow_color_blend = vec3(0.0);
- float pssm_blend;
- float shadow2;
+ } else { //no soft shadows
+ vec4 pssm_coord;
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);
- }
+ BIAS_FUNC(v, 0)
- 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;
+ pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
} 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);
+ BIAS_FUNC(v, 1)
- shadow_color_blend = directional_lights.data[i].shadow_color3.rgb;
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
} 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_blend = sqrt(pssm_blend);
-
- shadow = mix(shadow, shadow2, pssm_blend);
- shadow_color = mix(shadow_color, shadow_color_blend, pssm_blend);
- }
-
- shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
-
-#undef BIAS_FUNC
- }
-#else
- // Soft shadow disabled version
-
- if (directional_lights.data[i].shadow_enabled) {
- float depth_z = -vertex.z;
-
- vec4 pssm_coord;
- vec3 light_dir = directional_lights.data[i].direction;
- vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp))));
-
-#define BIAS_FUNC(m_var, m_idx) \
- m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
- vec3 normal_bias = base_normal_bias * directional_lights.data[i].shadow_normal_bias[m_idx]; \
- normal_bias -= light_dir * dot(light_dir, normal_bias); \
- m_var.xyz += normal_bias;
-
- 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);
-#ifdef LIGHT_TRANSMITTANCE_USED
- {
- vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0);
- vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex;
- trans_coord /= trans_coord.w;
-
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x;
-
- transmittance_z = z - shadow_z;
- }
-#endif
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
- vec4 v = vec4(vertex, 1.0);
-
- BIAS_FUNC(v, 1)
-
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
-#ifdef LIGHT_TRANSMITTANCE_USED
- {
- vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0);
- vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex;
- trans_coord /= trans_coord.w;
-
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y;
-
- transmittance_z = z - shadow_z;
- }
-#endif
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
- vec4 v = vec4(vertex, 1.0);
-
- BIAS_FUNC(v, 2)
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
-#ifdef LIGHT_TRANSMITTANCE_USED
- {
- vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0);
- vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex;
- trans_coord /= trans_coord.w;
-
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z;
-
- transmittance_z = z - shadow_z;
- }
-#endif
-
- } else {
- vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 2)
- BIAS_FUNC(v, 3)
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
-#ifdef LIGHT_TRANSMITTANCE_USED
- {
- vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0);
- vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex;
- trans_coord /= trans_coord.w;
+ } else {
+ vec4 v = vec4(vertex, 1.0);
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w;
+ BIAS_FUNC(v, 3)
- transmittance_z = z - shadow_z;
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
}
-#endif
- }
- pssm_coord /= pssm_coord.w;
+ pssm_coord /= pssm_coord.w;
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+
+ if (directional_lights.data[i].blend_splits) {
+ float pssm_blend;
+
+ 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_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
+ } 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_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+ } 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_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
+ } else {
+ pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
+ }
- if (directional_lights.data[i].blend_splits) {
- float pssm_blend;
+ pssm_coord /= pssm_coord.w;
- 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_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
- } 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_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
- } 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_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
- } else {
- pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
+ float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ shadow = mix(shadow, shadow2, pssm_blend);
}
-
- pssm_coord /= pssm_coord.w;
-
- float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
- shadow = mix(shadow, shadow2, pssm_blend);
}
shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
#undef BIAS_FUNC
- }
-#endif
+ } // shadows
if (i < 4) {
shadow0 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << (i * 8);
@@ -1540,6 +1458,7 @@ void main() {
shadow1 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << ((i - 4) * 8);
}
}
+#endif // SHADOWS_DISABLED
for (uint i = 0; i < 8; i++) {
if (i >= scene_data.directional_light_count) {
@@ -1562,8 +1481,8 @@ void main() {
trans_coord /= trans_coord.w;
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x;
+ shadow_z *= directional_lights.data[i].shadow_z_range.x;
+ float z = trans_coord.z * directional_lights.data[i].shadow_z_range.x;
transmittance_z = z - shadow_z;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
@@ -1572,8 +1491,8 @@ void main() {
trans_coord /= trans_coord.w;
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y;
+ shadow_z *= directional_lights.data[i].shadow_z_range.y;
+ float z = trans_coord.z * directional_lights.data[i].shadow_z_range.y;
transmittance_z = z - shadow_z;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
@@ -1582,8 +1501,8 @@ void main() {
trans_coord /= trans_coord.w;
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z;
+ shadow_z *= directional_lights.data[i].shadow_z_range.z;
+ float z = trans_coord.z * directional_lights.data[i].shadow_z_range.z;
transmittance_z = z - shadow_z;
@@ -1593,221 +1512,208 @@ void main() {
trans_coord /= trans_coord.w;
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w;
+ shadow_z *= directional_lights.data[i].shadow_z_range.w;
+ float z = trans_coord.z * directional_lights.data[i].shadow_z_range.w;
transmittance_z = z - shadow_z;
}
+ }
#endif
- float shadow = 1.0;
+ float shadow = 1.0;
+#ifndef SHADOWS_DISABLED
+ if (i < 4) {
+ shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0;
+ } else {
+ shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0;
+ }
+#endif
- if (i < 4) {
- shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0;
- } else {
- shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0;
- }
+ blur_shadow(shadow);
- blur_shadow(shadow);
+ float size_A = sc_use_light_soft_shadows ? directional_lights.data[i].size : 0.0;
- light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0,
+ light_compute(normal, directional_lights.data[i].direction, normalize(view), size_A, directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
- backlight,
+ backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
- transmittance_color,
- transmittance_depth,
- transmittance_curve,
- transmittance_boost,
- transmittance_z,
+ transmittance_color,
+ transmittance_depth,
+ transmittance_boost,
+ transmittance_z,
#endif
#ifdef LIGHT_RIM_USED
- rim, rim_tint, albedo,
+ rim, rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_gloss,
+ clearcoat, clearcoat_gloss,
#endif
#ifdef LIGHT_ANISOTROPY_USED
- binormal, tangent, anisotropy,
+ binormal, tangent, anisotropy,
#endif
-#ifdef USE_SOFT_SHADOW
- directional_lights.data[i].size,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
- diffuse_light,
- specular_light);
- }
+ diffuse_light,
+ specular_light);
}
+ }
- { //omni lights
+ { //omni lights
- uint cluster_omni_offset = cluster_offset;
+ uint cluster_omni_offset = cluster_offset;
- uint item_min;
- uint item_max;
- uint item_from;
- uint item_to;
+ uint item_min;
+ uint item_max;
+ uint item_from;
+ uint item_to;
- cluster_get_item_range(cluster_omni_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+ cluster_get_item_range(cluster_omni_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
- item_from = subgroupBroadcastFirst(subgroupMin(item_from));
- item_to = subgroupBroadcastFirst(subgroupMax(item_to));
+ item_from = subgroupBroadcastFirst(subgroupMin(item_from));
+ item_to = subgroupBroadcastFirst(subgroupMax(item_to));
#endif
- for (uint i = item_from; i < item_to; i++) {
- uint mask = cluster_buffer.data[cluster_omni_offset + i];
- mask &= cluster_get_range_clip_mask(i, item_min, item_max);
+ for (uint i = item_from; i < item_to; i++) {
+ uint mask = cluster_buffer.data[cluster_omni_offset + i];
+ mask &= cluster_get_range_clip_mask(i, item_min, item_max);
#ifdef USE_SUBGROUPS
- uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
+ uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
#else
uint merged_mask = mask;
#endif
- while (merged_mask != 0) {
- uint bit = findMSB(merged_mask);
- merged_mask &= ~(1 << bit);
+ while (merged_mask != 0) {
+ uint bit = findMSB(merged_mask);
+ merged_mask &= ~(1 << bit);
#ifdef USE_SUBGROUPS
- if (((1 << bit) & mask) == 0) { //do not process if not originally here
- continue;
- }
+ if (((1 << bit) & mask) == 0) { //do not process if not originally here
+ continue;
+ }
#endif
- uint light_index = 32 * i + bit;
+ uint light_index = 32 * i + bit;
- if (!bool(omni_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) {
- continue; //not masked
- }
+ if (!bool(omni_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) {
+ continue; //not masked
+ }
- if (omni_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
- continue; // Statically baked light and object uses lightmap, skip
- }
+ if (omni_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
+ continue; // Statically baked light and object uses lightmap, skip
+ }
- float shadow = light_process_omni_shadow(light_index, vertex, view);
+ float shadow = light_process_omni_shadow(light_index, vertex, normal);
- shadow = blur_shadow(shadow);
+ shadow = blur_shadow(shadow);
- light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow,
+ light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
- backlight,
+ backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
- transmittance_color,
- transmittance_depth,
- transmittance_curve,
- transmittance_boost,
+ transmittance_color,
+ transmittance_depth,
+ transmittance_boost,
#endif
#ifdef LIGHT_RIM_USED
- rim,
- rim_tint,
- albedo,
+ rim,
+ rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_gloss,
+ clearcoat, clearcoat_gloss,
#endif
#ifdef LIGHT_ANISOTROPY_USED
- tangent, binormal, anisotropy,
+ tangent, binormal, anisotropy,
#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
- diffuse_light, specular_light);
- }
+ diffuse_light, specular_light);
}
}
+ }
- { //spot lights
+ { //spot lights
- uint cluster_spot_offset = cluster_offset + scene_data.cluster_type_size;
+ uint cluster_spot_offset = cluster_offset + scene_data.cluster_type_size;
- uint item_min;
- uint item_max;
- uint item_from;
- uint item_to;
+ uint item_min;
+ uint item_max;
+ uint item_from;
+ uint item_to;
- cluster_get_item_range(cluster_spot_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+ cluster_get_item_range(cluster_spot_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
- item_from = subgroupBroadcastFirst(subgroupMin(item_from));
- item_to = subgroupBroadcastFirst(subgroupMax(item_to));
+ item_from = subgroupBroadcastFirst(subgroupMin(item_from));
+ item_to = subgroupBroadcastFirst(subgroupMax(item_to));
#endif
- for (uint i = item_from; i < item_to; i++) {
- uint mask = cluster_buffer.data[cluster_spot_offset + i];
- mask &= cluster_get_range_clip_mask(i, item_min, item_max);
+ for (uint i = item_from; i < item_to; i++) {
+ uint mask = cluster_buffer.data[cluster_spot_offset + i];
+ mask &= cluster_get_range_clip_mask(i, item_min, item_max);
#ifdef USE_SUBGROUPS
- uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
+ uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
#else
uint merged_mask = mask;
#endif
- while (merged_mask != 0) {
- uint bit = findMSB(merged_mask);
- merged_mask &= ~(1 << bit);
+ while (merged_mask != 0) {
+ uint bit = findMSB(merged_mask);
+ merged_mask &= ~(1 << bit);
#ifdef USE_SUBGROUPS
- if (((1 << bit) & mask) == 0) { //do not process if not originally here
- continue;
- }
+ if (((1 << bit) & mask) == 0) { //do not process if not originally here
+ continue;
+ }
#endif
- uint light_index = 32 * i + bit;
+ uint light_index = 32 * i + bit;
- if (!bool(spot_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) {
- continue; //not masked
- }
+ if (!bool(spot_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) {
+ continue; //not masked
+ }
- if (spot_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
- continue; // Statically baked light and object uses lightmap, skip
- }
+ if (spot_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
+ continue; // Statically baked light and object uses lightmap, skip
+ }
- float shadow = light_process_spot_shadow(light_index, vertex, view);
+ float shadow = light_process_spot_shadow(light_index, vertex, normal);
- shadow = blur_shadow(shadow);
+ shadow = blur_shadow(shadow);
- light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow,
+ light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
- backlight,
+ backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
- transmittance_color,
- transmittance_depth,
- transmittance_curve,
- transmittance_boost,
+ transmittance_color,
+ transmittance_depth,
+ transmittance_boost,
#endif
#ifdef LIGHT_RIM_USED
- rim,
- rim_tint,
- albedo,
+ rim,
+ rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_gloss,
+ clearcoat, clearcoat_gloss,
#endif
#ifdef LIGHT_ANISOTROPY_USED
- tangent, binormal, anisotropy,
+ tangent, binormal, anisotropy,
#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
- diffuse_light, specular_light);
- }
+ diffuse_light, specular_light);
}
}
+ }
#ifdef USE_SHADOW_TO_OPACITY
- alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
+ alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
#if defined(ALPHA_SCISSOR_USED)
- if (alpha < alpha_scissor) {
- discard;
- }
+ if (alpha < alpha_scissor) {
+ discard;
+ }
#endif // ALPHA_SCISSOR_USED
#ifdef USE_OPAQUE_PREPASS
- if (alpha < opaque_prepass_threshold) {
- discard;
- }
+ if (alpha < scene_data.opaque_prepass_threshold) {
+ discard;
+ }
#endif // USE_OPAQUE_PREPASS
@@ -1819,126 +1725,130 @@ void main() {
#ifdef MODE_RENDER_SDF
- {
- vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz;
- ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size));
-
- uint albedo16 = 0x1; //solid flag
- albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11;
- albedo16 |= clamp(uint(albedo.g * 31.0), 0, 31) << 6;
- albedo16 |= clamp(uint(albedo.b * 31.0), 0, 31) << 1;
-
- imageStore(albedo_volume_grid, grid_pos, uvec4(albedo16));
-
- uint facing_bits = 0;
- const vec3 aniso_dir[6] = vec3[](
- vec3(1, 0, 0),
- vec3(0, 1, 0),
- vec3(0, 0, 1),
- vec3(-1, 0, 0),
- vec3(0, -1, 0),
- vec3(0, 0, -1));
-
- vec3 cam_normal = mat3(scene_data.camera_matrix) * normalize(normal_interp);
-
- float closest_dist = -1e20;
-
- for (uint i = 0; i < 6; i++) {
- float d = dot(cam_normal, aniso_dir[i]);
- if (d > closest_dist) {
- closest_dist = d;
- facing_bits = (1 << i);
- }
+ {
+ vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz;
+ ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size));
+
+ uint albedo16 = 0x1; //solid flag
+ albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11;
+ albedo16 |= clamp(uint(albedo.g * 31.0), 0, 31) << 6;
+ albedo16 |= clamp(uint(albedo.b * 31.0), 0, 31) << 1;
+
+ imageStore(albedo_volume_grid, grid_pos, uvec4(albedo16));
+
+ uint facing_bits = 0;
+ const vec3 aniso_dir[6] = vec3[](
+ vec3(1, 0, 0),
+ vec3(0, 1, 0),
+ vec3(0, 0, 1),
+ vec3(-1, 0, 0),
+ vec3(0, -1, 0),
+ vec3(0, 0, -1));
+
+ vec3 cam_normal = mat3(scene_data.camera_matrix) * normalize(normal_interp);
+
+ float closest_dist = -1e20;
+
+ for (uint i = 0; i < 6; i++) {
+ float d = dot(cam_normal, aniso_dir[i]);
+ if (d > closest_dist) {
+ closest_dist = d;
+ facing_bits = (1 << i);
}
+ }
- imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits
+#ifdef MOLTENVK_USED
+ imageStore(geom_facing_grid, grid_pos, uvec4(imageLoad(geom_facing_grid, grid_pos).r | facing_bits)); //store facing bits
+#else
+ imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits
+#endif
- if (length(emission) > 0.001) {
- float lumas[6];
- vec3 light_total = vec3(0);
+ if (length(emission) > 0.001) {
+ float lumas[6];
+ vec3 light_total = vec3(0);
- for (int i = 0; i < 6; i++) {
- float strength = max(0.0, dot(cam_normal, aniso_dir[i]));
- vec3 light = emission * strength;
- light_total += light;
- lumas[i] = max(light.r, max(light.g, light.b));
- }
+ for (int i = 0; i < 6; i++) {
+ float strength = max(0.0, dot(cam_normal, aniso_dir[i]));
+ vec3 light = emission * strength;
+ light_total += light;
+ lumas[i] = max(light.r, max(light.g, light.b));
+ }
- float luma_total = max(light_total.r, max(light_total.g, light_total.b));
+ float luma_total = max(light_total.r, max(light_total.g, light_total.b));
- uint light_aniso = 0;
+ uint light_aniso = 0;
- for (int i = 0; i < 6; i++) {
- light_aniso |= min(31, uint((lumas[i] / luma_total) * 31.0)) << (i * 5);
- }
+ for (int i = 0; i < 6; i++) {
+ light_aniso |= min(31, uint((lumas[i] / luma_total) * 31.0)) << (i * 5);
+ }
- //compress to RGBE9995 to save space
+ //compress to RGBE9995 to save space
- const float pow2to9 = 512.0f;
- const float B = 15.0f;
- const float N = 9.0f;
- const float LN2 = 0.6931471805599453094172321215;
+ const float pow2to9 = 512.0f;
+ const float B = 15.0f;
+ const float N = 9.0f;
+ const float LN2 = 0.6931471805599453094172321215;
- float cRed = clamp(light_total.r, 0.0, 65408.0);
- float cGreen = clamp(light_total.g, 0.0, 65408.0);
- float cBlue = clamp(light_total.b, 0.0, 65408.0);
+ float cRed = clamp(light_total.r, 0.0, 65408.0);
+ float cGreen = clamp(light_total.g, 0.0, 65408.0);
+ float cBlue = clamp(light_total.b, 0.0, 65408.0);
- float cMax = max(cRed, max(cGreen, cBlue));
+ float cMax = max(cRed, max(cGreen, cBlue));
- float expp = max(-B - 1.0f, floor(log(cMax) / LN2)) + 1.0f + B;
+ float expp = max(-B - 1.0f, floor(log(cMax) / LN2)) + 1.0f + B;
- float sMax = floor((cMax / pow(2.0f, expp - B - N)) + 0.5f);
+ float sMax = floor((cMax / pow(2.0f, expp - B - N)) + 0.5f);
- float exps = expp + 1.0f;
+ float exps = expp + 1.0f;
- if (0.0 <= sMax && sMax < pow2to9) {
- exps = expp;
- }
+ if (0.0 <= sMax && sMax < pow2to9) {
+ exps = expp;
+ }
- float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f);
- float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f);
- float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f);
- //store as 8985 to have 2 extra neighbour bits
- uint light_rgbe = ((uint(sRed) & 0x1FF) >> 1) | ((uint(sGreen) & 0x1FF) << 8) | (((uint(sBlue) & 0x1FF) >> 1) << 17) | ((uint(exps) & 0x1F) << 25);
+ float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f);
+ float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f);
+ float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f);
+ //store as 8985 to have 2 extra neighbour bits
+ uint light_rgbe = ((uint(sRed) & 0x1FF) >> 1) | ((uint(sGreen) & 0x1FF) << 8) | (((uint(sBlue) & 0x1FF) >> 1) << 17) | ((uint(exps) & 0x1F) << 25);
- imageStore(emission_grid, grid_pos, uvec4(light_rgbe));
- imageStore(emission_aniso_grid, grid_pos, uvec4(light_aniso));
- }
+ imageStore(emission_grid, grid_pos, uvec4(light_rgbe));
+ imageStore(emission_aniso_grid, grid_pos, uvec4(light_aniso));
}
+ }
#endif
#ifdef MODE_RENDER_MATERIAL
- albedo_output_buffer.rgb = albedo;
- albedo_output_buffer.a = alpha;
+ albedo_output_buffer.rgb = albedo;
+ albedo_output_buffer.a = alpha;
- normal_output_buffer.rgb = normal * 0.5 + 0.5;
- normal_output_buffer.a = 0.0;
- depth_output_buffer.r = -vertex.z;
+ normal_output_buffer.rgb = normal * 0.5 + 0.5;
+ normal_output_buffer.a = 0.0;
+ depth_output_buffer.r = -vertex.z;
- orm_output_buffer.r = ao;
- orm_output_buffer.g = roughness;
- orm_output_buffer.b = metallic;
- orm_output_buffer.a = sss_strength;
+ orm_output_buffer.r = ao;
+ orm_output_buffer.g = roughness;
+ orm_output_buffer.b = metallic;
+ orm_output_buffer.a = sss_strength;
- emission_output_buffer.rgb = emission;
- emission_output_buffer.a = 0.0;
+ emission_output_buffer.rgb = emission;
+ emission_output_buffer.a = 0.0;
#endif
#ifdef MODE_RENDER_NORMAL_ROUGHNESS
- normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness);
-
-#ifdef MODE_RENDER_GIPROBE
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes
- uint index1 = instances.data[instance_index].gi_offset & 0xFFFF;
- uint index2 = instances.data[instance_index].gi_offset >> 16;
- giprobe_buffer.x = index1 & 0xFF;
- giprobe_buffer.y = index2 & 0xFF;
- } else {
- giprobe_buffer.x = 0xFF;
- giprobe_buffer.y = 0xFF;
- }
+ normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness);
+
+#ifdef MODE_RENDER_VOXEL_GI
+ if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_VOXEL_GI)) { // process voxel_gi_instances
+ uint index1 = instances.data[instance_index].gi_offset & 0xFFFF;
+ uint index2 = instances.data[instance_index].gi_offset >> 16;
+ voxel_gi_buffer.x = index1 & 0xFF;
+ voxel_gi_buffer.y = index2 & 0xFF;
+ } else {
+ voxel_gi_buffer.x = 0xFF;
+ voxel_gi_buffer.y = 0xFF;
+ }
#endif
#endif //MODE_RENDER_NORMAL_ROUGHNESS
@@ -1991,9 +1901,8 @@ void main() {
// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
- ;
#endif //MODE_MULTIPLE_RENDER_TARGETS
#endif //MODE_RENDER_DEPTH
- }
+}
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
index ca75d6300e..be29cf4f58 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
@@ -1,7 +1,7 @@
#define M_PI 3.14159265359
#define ROUGHNESS_MAX_LOD 5
-#define MAX_GI_PROBES 8
+#define MAX_VOXEL_GI_INSTANCES 8
#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic)
@@ -15,7 +15,7 @@
#include "cluster_data_inc.glsl"
#include "decal_data_inc.glsl"
-#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_GIPROBE) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED)
+#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED)
#ifndef NORMAL_USED
#define NORMAL_USED
#endif
@@ -52,38 +52,42 @@ layout(set = 0, binding = 1) uniform sampler material_samplers[12];
layout(set = 0, binding = 2) uniform sampler shadow_sampler;
+layout(set = 0, binding = 3) uniform sampler decal_sampler;
+
+layout(set = 0, binding = 4) uniform sampler light_projector_sampler;
+
+#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 5)
#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6)
#define INSTANCE_FLAGS_USE_SDFGI (1 << 7)
#define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 8)
#define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 9)
#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 10)
-#define INSTANCE_FLAGS_USE_GIPROBE (1 << 11)
+#define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 11)
#define INSTANCE_FLAGS_MULTIMESH (1 << 12)
#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13)
#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14)
#define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15)
#define INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT 16
+#define INSTANCE_FLAGS_FADE_SHIFT 24
//3 bits of stride
#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF
-#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 24)
-
-layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
+layout(set = 0, binding = 5, std430) restrict readonly buffer OmniLights {
LightData data[];
}
omni_lights;
-layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
+layout(set = 0, binding = 6, std430) restrict readonly buffer SpotLights {
LightData data[];
}
spot_lights;
-layout(set = 0, binding = 5, std430) restrict readonly buffer ReflectionProbeData {
+layout(set = 0, binding = 7, std430) restrict readonly buffer ReflectionProbeData {
ReflectionData data[];
}
reflections;
-layout(set = 0, binding = 6, std140) uniform DirectionalLights {
+layout(set = 0, binding = 8, std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
directional_lights;
@@ -95,7 +99,7 @@ struct Lightmap {
mat3 normal_xform;
};
-layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
+layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps {
Lightmap data[];
}
lightmaps;
@@ -104,32 +108,32 @@ struct LightmapCapture {
vec4 sh[9];
};
-layout(set = 0, binding = 8, std140) restrict readonly buffer LightmapCaptures {
+layout(set = 0, binding = 10, std140) restrict readonly buffer LightmapCaptures {
LightmapCapture data[];
}
lightmap_captures;
-layout(set = 0, binding = 9) uniform texture2D decal_atlas;
-layout(set = 0, binding = 10) uniform texture2D decal_atlas_srgb;
+layout(set = 0, binding = 11) uniform texture2D decal_atlas;
+layout(set = 0, binding = 12) uniform texture2D decal_atlas_srgb;
-layout(set = 0, binding = 11, std430) restrict readonly buffer Decals {
+layout(set = 0, binding = 13, std430) restrict readonly buffer Decals {
DecalData data[];
}
decals;
-layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableData {
+layout(set = 0, binding = 14, std430) restrict readonly buffer GlobalVariableData {
vec4 data[];
}
global_variables;
-struct SDFGIProbeCascadeData {
+struct SDFVoxelGICascadeData {
vec3 position;
float to_probe;
ivec3 probe_world_offset;
float to_cell; // 1/bounds * grid_size
};
-layout(set = 0, binding = 13, std140) uniform SDFGI {
+layout(set = 0, binding = 15, std140) uniform SDFGI {
vec3 grid_size;
uint max_cascades;
@@ -153,7 +157,7 @@ layout(set = 0, binding = 13, std140) uniform SDFGI {
vec3 cascade_probe_size;
uint pad5;
- SDFGIProbeCascadeData cascades[SDFGI_MAX_CASCADES];
+ SDFVoxelGICascadeData cascades[SDFGI_MAX_CASCADES];
}
sdfgi;
@@ -174,17 +178,12 @@ layout(set = 1, binding = 0, std140) uniform SceneData {
uint cluster_type_size;
uint max_cluster_element_count_div_32;
- //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted
+ // Use vec4s because std140 doesn't 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;
float ambient_color_sky_mix;
@@ -209,9 +208,8 @@ layout(set = 1, binding = 0, std140) uniform SceneData {
float roughness_limiter_amount;
float roughness_limiter_limit;
- uvec2 roughness_limiter_pad;
-
- vec4 ao_color;
+ float opaque_prepass_threshold;
+ uint roughness_limiter_pad;
mat4 sdf_to_bounds;
@@ -275,7 +273,7 @@ layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas;
layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
-layout(set = 1, binding = 7) uniform texture3D gi_probe_textures[MAX_GI_PROBES];
+layout(set = 1, binding = 7) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
layout(set = 1, binding = 8, std430) buffer restrict readonly ClusterBuffer {
uint data[];
@@ -306,7 +304,7 @@ layout(set = 1, binding = 14) uniform texture2D reflection_buffer;
layout(set = 1, binding = 15) uniform texture2DArray sdfgi_lightprobe_texture;
layout(set = 1, binding = 16) uniform texture3D sdfgi_occlusion_cascades;
-struct GIProbeData {
+struct VoxelGIData {
mat4 xform;
vec3 bounds;
float dynamic_range;
@@ -322,10 +320,10 @@ struct GIProbeData {
uint mipmaps;
};
-layout(set = 1, binding = 17, std140) uniform GIProbes {
- GIProbeData data[MAX_GI_PROBES];
+layout(set = 1, binding = 17, std140) uniform VoxelGIs {
+ VoxelGIData data[MAX_VOXEL_GI_INSTANCES];
}
-gi_probes;
+voxel_gi_instances;
layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
index b41f16cbe7..c88bd0a14b 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
@@ -48,24 +48,24 @@ vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3
return color;
}
-void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) {
- position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz;
- ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz);
- normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz);
+void voxel_gi_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) {
+ position = (voxel_gi_instances.data[index].xform * vec4(position, 1.0)).xyz;
+ ref_vec = normalize((voxel_gi_instances.data[index].xform * vec4(ref_vec, 0.0)).xyz);
+ normal = normalize((voxel_gi_instances.data[index].xform * vec4(normal, 0.0)).xyz);
- position += normal * gi_probes.data[index].normal_bias;
+ position += normal * voxel_gi_instances.data[index].normal_bias;
//this causes corrupted pixels, i have no idea why..
- if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) {
+ if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, voxel_gi_instances.data[index].bounds))))) {
return;
}
- vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0);
+ vec3 blendv = abs(position / voxel_gi_instances.data[index].bounds * 2.0 - 1.0);
float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0);
//float blend=1.0;
- float max_distance = length(gi_probes.data[index].bounds);
- vec3 cell_size = 1.0 / gi_probes.data[index].bounds;
+ float max_distance = length(voxel_gi_instances.data[index].bounds);
+ vec3 cell_size = 1.0 / voxel_gi_instances.data[index].bounds;
//radiance
@@ -83,26 +83,26 @@ void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3
vec3 light = vec3(0.0);
for (int i = 0; i < MAX_CONE_DIRS; i++) {
- vec3 dir = normalize((gi_probes.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz);
+ vec3 dir = normalize((voxel_gi_instances.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz);
- vec4 cone_light = voxel_cone_trace_45_degrees(gi_probe_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+ vec4 cone_light = voxel_cone_trace_45_degrees(voxel_gi_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, voxel_gi_instances.data[index].bias);
- if (gi_probes.data[index].blend_ambient) {
+ if (voxel_gi_instances.data[index].blend_ambient) {
cone_light.rgb = mix(ambient, cone_light.rgb, min(1.0, cone_light.a / 0.95));
}
light += cone_weights[i] * cone_light.rgb;
}
- light *= gi_probes.data[index].dynamic_range;
+ light *= voxel_gi_instances.data[index].dynamic_range;
out_diff += vec4(light * blend, blend);
//irradiance
- vec4 irr_light = voxel_cone_trace(gi_probe_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias);
- if (gi_probes.data[index].blend_ambient) {
+ vec4 irr_light = voxel_cone_trace(voxel_gi_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, voxel_gi_instances.data[index].bias);
+ if (voxel_gi_instances.data[index].blend_ambient) {
irr_light.rgb = mix(environment, irr_light.rgb, min(1.0, irr_light.a / 0.95));
}
- irr_light.rgb *= gi_probes.data[index].dynamic_range;
+ irr_light.rgb *= voxel_gi_instances.data[index].dynamic_range;
//irr_light=vec3(0.0);
out_spec += vec4(irr_light.rgb * blend, blend);
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
index 32a86cb166..d22f936a35 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -73,19 +73,18 @@ 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 f0, uint orms, float specular_amount,
+void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount, vec3 albedo, inout float alpha,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
vec4 transmittance_color,
float transmittance_depth,
- float transmittance_curve,
float transmittance_boost,
float transmittance_z,
#endif
#ifdef LIGHT_RIM_USED
- float rim, float rim_tint, vec3 rim_color,
+ float rim, float rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
float clearcoat, float clearcoat_gloss,
@@ -93,14 +92,13 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
#ifdef LIGHT_ANISOTROPY_USED
vec3 B, vec3 T, float anisotropy,
#endif
-#ifdef USE_SOFT_SHADOWS
- float A,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- inout float alpha,
-#endif
inout vec3 diffuse_light, inout vec3 specular_light) {
+ vec4 orms_unpacked = unpackUnorm4x8(orms);
+
+ float roughness = orms_unpacked.y;
+ float metallic = orms_unpacked.z;
+
#if defined(LIGHT_CODE_USED)
// light is written by the light shader
@@ -112,11 +110,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
#else
-#ifdef USE_SOFT_SHADOWS
float NdotL = min(A + dot(N, L), 1.0);
-#else
- float NdotL = dot(N, L);
-#endif
float cNdotL = max(NdotL, 0.0); // clamped NdotL
float NdotV = dot(N, V);
float cNdotV = max(NdotV, 0.0);
@@ -126,30 +120,15 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
#endif
#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
-#ifdef USE_SOFT_SHADOWS
float cNdotH = clamp(A + dot(N, H), 0.0, 1.0);
-#else
- float cNdotH = clamp(dot(N, H), 0.0, 1.0);
-#endif
#endif
#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
-#ifdef USE_SOFT_SHADOWS
float cLdotH = clamp(A + dot(L, H), 0.0, 1.0);
-#else
- float cLdotH = clamp(dot(L, H), 0.0, 1.0);
-#endif
#endif
- float metallic = unpackUnorm4x8(orms).z;
if (metallic < 1.0) {
- float roughness = unpackUnorm4x8(orms).y;
-
-#if defined(DIFFUSE_OREN_NAYAR)
- vec3 diffuse_brdf_NL;
-#else
float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance
-#endif
#if defined(DIFFUSE_LAMBERT_WRAP)
// energy conserving lambert wrap shader
@@ -189,43 +168,37 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
#if defined(LIGHT_RIM_USED)
float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0));
- diffuse_light += rim_light * rim * mix(vec3(1.0), rim_color, rim_tint) * light_color;
+ diffuse_light += rim_light * rim * mix(vec3(1.0), albedo, rim_tint) * light_color;
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
-#ifdef SSS_MODE_SKIN
-
{
+#ifdef SSS_MODE_SKIN
float scale = 8.25 / transmittance_depth;
float d = scale * abs(transmittance_z);
float dd = -d * d;
vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
- vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
- vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
- vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
- vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
- vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
+ vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
+ vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
+ vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
+ vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
+ vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI);
- }
#else
- if (transmittance_depth > 0.0) {
- float fade = clamp(abs(transmittance_z / transmittance_depth), 0.0, 1.0);
-
- fade = pow(max(0.0, 1.0 - fade), transmittance_curve);
- fade *= clamp(transmittance_boost - NdotL, 0.0, 1.0);
-
- diffuse_light += transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade;
+ float scale = 8.25 / transmittance_depth;
+ float d = scale * abs(transmittance_z);
+ float dd = -d * d;
+ diffuse_light += exp(dd) * transmittance_color.rgb * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI);
+#endif
}
-
-#endif //SSS_MODE_SKIN
+#else
#endif //LIGHT_TRANSMITTANCE_USED
}
- float roughness = unpackUnorm4x8(orms).y;
if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely
// D
@@ -234,11 +207,10 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
//normalized blinn
float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
- float blinn = pow(cNdotH, shininess) * cNdotL;
- blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
- float intensity = blinn;
+ float blinn = pow(cNdotH, shininess);
+ blinn *= (shininess + 2.0) * (1.0 / (8.0 * M_PI));
- specular_light += light_color * intensity * attenuation * specular_amount;
+ specular_light += light_color * attenuation * specular_amount * blinn * f0 * orms_unpacked.w;
#elif defined(SPECULAR_PHONG)
@@ -246,10 +218,9 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
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));
- float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75);
+ phong *= (shininess + 1.0) * (1.0 / (8.0 * M_PI));
- specular_light += light_color * intensity * attenuation * specular_amount;
+ specular_light += light_color * attenuation * specular_amount * phong * f0 * orms_unpacked.w;
#elif defined(SPECULAR_TOON)
@@ -307,16 +278,16 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
}
#ifdef USE_SHADOW_TO_OPACITY
- alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0));
+ alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0));
#endif
#endif //defined(LIGHT_CODE_USED)
}
-#ifndef USE_NO_SHADOWS
+#ifndef SHADOWS_DISABLED
// Interleaved Gradient Noise
-// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
+// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
float quick_hash(vec2 pos) {
const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
return fract(magic.z * fract(dot(pos, magic.xy)));
@@ -327,7 +298,7 @@ float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, ve
float depth = coord.z;
//if only one sample is taken, take it from the center
- if (scene_data.directional_soft_shadow_samples == 1) {
+ if (sc_directional_soft_shadow_samples == 0) {
return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
}
@@ -341,19 +312,19 @@ float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, ve
float avg = 0.0;
- for (uint i = 0; i < scene_data.directional_soft_shadow_samples; i++) {
+ for (uint i = 0; i < sc_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));
+ return avg * (1.0 / float(sc_directional_soft_shadow_samples));
}
-float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
+float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec3 coord) {
vec2 pos = coord.xy;
float depth = coord.z;
//if only one sample is taken, take it from the center
- if (scene_data.soft_shadow_samples == 1) {
+ if (sc_soft_shadow_samples == 0) {
return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
}
@@ -367,11 +338,54 @@ float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
float avg = 0.0;
- for (uint i = 0; i < scene_data.soft_shadow_samples; i++) {
+ for (uint i = 0; i < sc_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));
+ return avg * (1.0 / float(sc_soft_shadow_samples));
+}
+
+float sample_omni_pcf_shadow(texture2D shadow, float blur_scale, vec2 coord, vec4 uv_rect, vec2 flip_offset, float depth) {
+ //if only one sample is taken, take it from the center
+ if (sc_soft_shadow_samples == 0) {
+ vec2 pos = coord * 0.5 + 0.5;
+ pos = uv_rect.xy + pos * uv_rect.zw;
+ 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;
+ vec2 offset_scale = blur_scale * 2.0 * scene_data.shadow_atlas_pixel_size / uv_rect.zw;
+
+ for (uint i = 0; i < sc_soft_shadow_samples; i++) {
+ vec2 offset = offset_scale * (disk_rotation * scene_data.soft_shadow_kernel[i].xy);
+ vec2 sample_coord = coord + offset;
+
+ float sample_coord_length_sqaured = dot(sample_coord, sample_coord);
+ bool do_flip = sample_coord_length_sqaured > 1.0;
+
+ if (do_flip) {
+ float len = sqrt(sample_coord_length_sqaured);
+ sample_coord = sample_coord * (2.0 / len - 1.0);
+ }
+
+ sample_coord = sample_coord * 0.5 + 0.5;
+ sample_coord = uv_rect.xy + sample_coord * uv_rect.zw;
+
+ if (do_flip) {
+ sample_coord += flip_offset;
+ }
+ avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(sample_coord, depth, 1.0));
+ }
+
+ return avg * (1.0 / float(sc_soft_shadow_samples));
}
float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) {
@@ -387,7 +401,7 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
}
- for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_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) {
@@ -403,12 +417,12 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
tex_scale *= penumbra;
float s = 0.0;
- for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_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);
+ return s / float(sc_directional_penumbra_shadow_samples);
} else {
//no blockers found, so no shadow
@@ -416,7 +430,7 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
}
}
-#endif //USE_NO_SHADOWS
+#endif // SHADOWS_DISABLED
float get_omni_attenuation(float distance, float inv_range, float decay) {
float nd = distance * inv_range;
@@ -428,29 +442,28 @@ float get_omni_attenuation(float distance, float inv_range, float decay) {
}
float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
-#ifndef USE_NO_SHADOWS
+#ifndef SHADOWS_DISABLED
if (omni_lights.data[idx].shadow_enabled) {
// there is a shadowmap
+ vec2 texel_size = scene_data.shadow_atlas_pixel_size;
+ vec4 base_uv_rect = omni_lights.data[idx].atlas_rect;
+ base_uv_rect.xy += texel_size;
+ base_uv_rect.zw -= texel_size * 2.0;
- vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
- float light_length = length(light_rel_vec);
+ // Omni lights use direction.xy to store to store the offset between the two paraboloid regions
+ vec2 flip_offset = omni_lights.data[idx].direction.xy;
- vec4 v = vec4(vertex, 1.0);
+ vec3 local_vert = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
- vec4 splane = (omni_lights.data[idx].shadow_matrix * v);
- float shadow_len = length(splane.xyz); //need to remember shadow len from here
+ float shadow_len = length(local_vert); //need to remember shadow len from here
+ vec3 shadow_dir = normalize(local_vert);
- {
- vec3 nofs = normal_interp * omni_lights.data[idx].shadow_normal_bias / omni_lights.data[idx].inv_radius;
- nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp))));
- v.xyz += nofs;
- splane = (omni_lights.data[idx].shadow_matrix * v);
- }
+ vec3 local_normal = normalize(mat3(omni_lights.data[idx].shadow_matrix) * normal);
+ vec3 normal_bias = local_normal * omni_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(local_normal, shadow_dir)));
float shadow;
-#ifdef USE_SOFT_SHADOWS
- if (omni_lights.data[idx].soft_shadow_size > 0.0) {
+ if (sc_use_light_soft_shadows && omni_lights.data[idx].soft_shadow_size > 0.0) {
//soft shadow
//find blocker
@@ -466,30 +479,29 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
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));
+ vec3 basis_normal = shadow_dir;
+ vec3 v0 = abs(basis_normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
+ vec3 tangent = normalize(cross(v0, basis_normal));
+ vec3 bitangent = normalize(cross(tangent, basis_normal));
float z_norm = shadow_len * omni_lights.data[idx].inv_radius;
tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_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;
+ vec3 pos = local_vert + tangent * disk.x + bitangent * disk.y;
pos = normalize(pos);
- vec4 uv_rect = omni_lights.data[idx].atlas_rect;
+
+ vec4 uv_rect = base_uv_rect;
if (pos.z >= 0.0) {
- pos.z += 1.0;
- uv_rect.y += uv_rect.w;
- } else {
- pos.z = 1.0 - pos.z;
+ uv_rect.xy += flip_offset;
}
+ pos.z = 1.0 + abs(pos.z);
pos.xy /= pos.z;
pos.xy = pos.xy * 0.5 + 0.5;
@@ -512,20 +524,20 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias;
shadow = 0.0;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_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;
+ vec3 pos = local_vert + tangent * disk.x + bitangent * disk.y;
pos = normalize(pos);
- vec4 uv_rect = omni_lights.data[idx].atlas_rect;
+ pos = normalize(pos + normal_bias);
+
+ vec4 uv_rect = base_uv_rect;
if (pos.z >= 0.0) {
- pos.z += 1.0;
- uv_rect.y += uv_rect.w;
- } else {
- pos.z = 1.0 - pos.z;
+ uv_rect.xy += flip_offset;
}
+ pos.z = 1.0 + abs(pos.z);
pos.xy /= pos.z;
pos.xy = pos.xy * 0.5 + 0.5;
@@ -533,36 +545,27 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0));
}
- shadow /= float(scene_data.penumbra_shadow_samples);
+ shadow /= float(sc_penumbra_shadow_samples);
} else {
//no blockers found, so no shadow
shadow = 1.0;
}
} else {
-#endif
- splane.xyz = normalize(splane.xyz);
- vec4 clamp_rect = omni_lights.data[idx].atlas_rect;
-
- if (splane.z >= 0.0) {
- splane.z += 1.0;
+ vec4 uv_rect = base_uv_rect;
- clamp_rect.y += clamp_rect.w;
-
- } else {
- splane.z = 1.0 - splane.z;
+ vec3 shadow_sample = normalize(shadow_dir + normal_bias);
+ if (shadow_sample.z >= 0.0) {
+ uv_rect.xy += flip_offset;
+ flip_offset *= -1.0;
}
- splane.xy /= splane.z;
-
- splane.xy = splane.xy * 0.5 + 0.5;
- splane.z = (shadow_len - omni_lights.data[idx].shadow_bias) * omni_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, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane);
-#ifdef USE_SOFT_SHADOWS
+ shadow_sample.z = 1.0 + abs(shadow_sample.z);
+ vec2 pos = shadow_sample.xy / shadow_sample.z;
+ float depth = shadow_len - omni_lights.data[idx].shadow_bias;
+ depth *= omni_lights.data[idx].inv_radius;
+ shadow = sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth);
}
-#endif
return shadow;
}
@@ -571,18 +574,17 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
return 1.0;
}
-void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow,
+void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
vec4 transmittance_color,
float transmittance_depth,
- float transmittance_curve,
float transmittance_boost,
#endif
#ifdef LIGHT_RIM_USED
- float rim, float rim_tint, vec3 rim_color,
+ float rim, float rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
float clearcoat, float clearcoat_gloss,
@@ -590,9 +592,6 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
#ifdef LIGHT_ANISOTROPY_USED
vec3 binormal, vec3 tangent, float anisotropy,
#endif
-#ifdef USE_SHADOW_TO_OPACITY
- inout float alpha,
-#endif
inout vec3 diffuse_light, inout vec3 specular_light) {
vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
float light_length = length(light_rel_vec);
@@ -600,14 +599,12 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
float light_attenuation = omni_attenuation;
vec3 color = omni_lights.data[idx].color;
-#ifdef USE_SOFT_SHADOWS
float size_A = 0.0;
- if (omni_lights.data[idx].size > 0.0) {
+ if (sc_use_light_soft_shadows && omni_lights.data[idx].size > 0.0) {
float t = omni_lights.data[idx].size / max(0.001, light_length);
size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
}
-#endif
#ifdef LIGHT_TRANSMITTANCE_USED
float transmittance_z = transmittance_depth; //no transmittance by default
@@ -618,20 +615,22 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
//redo shadowmapping, but shrink the model a bit to avoid arctifacts
vec4 splane = (omni_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * omni_lights.data[idx].transmittance_bias, 1.0));
- shadow_len = length(splane.xyz);
- splane = normalize(splane.xyz);
+ float shadow_len = length(splane.xyz);
+ splane.xyz = normalize(splane.xyz);
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 * omni_lights.data[idx].inv_radius;
splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
+ // splane.xy = clamp(splane.xy,clamp_rect.xy + scene_data.shadow_atlas_pixel_size,clamp_rect.xy + clamp_rect.zw - scene_data.shadow_atlas_pixel_size );
splane.w = 1.0; //needed? i think it should be 1 already
float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
@@ -639,78 +638,77 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
}
#endif
-#if 0
-
- if (omni_lights.data[idx].projector_rect != vec4(0.0)) {
+ if (sc_use_light_projector && omni_lights.data[idx].projector_rect != vec4(0.0)) {
vec3 local_v = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
local_v = normalize(local_v);
vec4 atlas_rect = omni_lights.data[idx].projector_rect;
if (local_v.z >= 0.0) {
- local_v.z += 1.0;
atlas_rect.y += atlas_rect.w;
-
- } else {
- local_v.z = 1.0 - local_v.z;
}
+ local_v.z = 1.0 + abs(local_v.z);
+
local_v.xy /= local_v.z;
local_v.xy = local_v.xy * 0.5 + 0.5;
vec2 proj_uv = local_v.xy * atlas_rect.zw;
- vec2 proj_uv_ddx;
- vec2 proj_uv_ddy;
- {
- vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz;
- local_v_ddx = normalize(local_v_ddx);
+ if (sc_projector_use_mipmaps) {
+ vec2 proj_uv_ddx;
+ vec2 proj_uv_ddy;
+ {
+ vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz;
+ local_v_ddx = normalize(local_v_ddx);
- if (local_v_ddx.z >= 0.0) {
- local_v_ddx.z += 1.0;
- } else {
- local_v_ddx.z = 1.0 - local_v_ddx.z;
- }
+ if (local_v_ddx.z >= 0.0) {
+ local_v_ddx.z += 1.0;
+ } else {
+ local_v_ddx.z = 1.0 - local_v_ddx.z;
+ }
- local_v_ddx.xy /= local_v_ddx.z;
- local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5;
+ local_v_ddx.xy /= local_v_ddx.z;
+ local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5;
- proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv;
+ proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv;
- vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz;
- local_v_ddy = normalize(local_v_ddy);
+ vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz;
+ local_v_ddy = normalize(local_v_ddy);
- if (local_v_ddy.z >= 0.0) {
- local_v_ddy.z += 1.0;
- } else {
- local_v_ddy.z = 1.0 - local_v_ddy.z;
- }
+ if (local_v_ddy.z >= 0.0) {
+ local_v_ddy.z += 1.0;
+ } else {
+ local_v_ddy.z = 1.0 - local_v_ddy.z;
+ }
- local_v_ddy.xy /= local_v_ddy.z;
- local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5;
+ local_v_ddy.xy /= local_v_ddy.z;
+ local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5;
- proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv;
- }
+ proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv;
+ }
- vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy);
- no_shadow = mix(no_shadow, proj.rgb, proj.a);
+ vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, light_projector_sampler), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy);
+ color *= proj.rgb * proj.a;
+ } else {
+ vec4 proj = textureLod(sampler2D(decal_atlas_srgb, light_projector_sampler), proj_uv + atlas_rect.xy, 0.0);
+ color *= proj.rgb * proj.a;
+ }
}
-#endif
light_attenuation *= shadow;
- light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
transmittance_color,
transmittance_depth,
- transmittance_curve,
transmittance_boost,
transmittance_z,
#endif
#ifdef LIGHT_RIM_USED
- rim * omni_attenuation, rim_tint, rim_color,
+ rim * omni_attenuation, rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
clearcoat, clearcoat_gloss,
@@ -718,47 +716,33 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
#ifdef LIGHT_ANISOTROPY_USED
binormal, tangent, anisotropy,
#endif
-#ifdef USE_SOFT_SHADOWS
- size_A,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
diffuse_light,
specular_light);
}
float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
-#ifndef USE_NO_SHADOWS
+#ifndef SHADOWS_DISABLED
if (spot_lights.data[idx].shadow_enabled) {
vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
float light_length = length(light_rel_vec);
vec3 spot_dir = spot_lights.data[idx].direction;
- //there is a shadowmap
- vec4 v = vec4(vertex, 1.0);
-
- v.xyz -= spot_dir * spot_lights.data[idx].shadow_bias;
-
- float z_norm = dot(spot_dir, -light_rel_vec) * spot_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)))) * spot_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 - spot_lights.data[idx].position) * spot_lights.data[idx].inv_radius;
+ vec3 shadow_dir = light_rel_vec / light_length;
+ vec3 normal_bias = normal * light_length * spot_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(normal, shadow_dir)));
- float shadow;
+ //there is a shadowmap
+ vec4 v = vec4(vertex + normal_bias, 1.0);
vec4 splane = (spot_lights.data[idx].shadow_matrix * v);
+ splane.z -= spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius);
splane /= splane.w;
-#ifdef USE_SOFT_SHADOWS
- if (spot_lights.data[idx].soft_shadow_size > 0.0) {
+ float shadow;
+ if (sc_use_light_soft_shadows && spot_lights.data[idx].soft_shadow_size > 0.0) {
//soft shadow
//find blocker
+ float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius;
vec2 shadow_uv = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy;
@@ -775,11 +759,11 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale;
vec2 clamp_max = spot_lights.data[idx].atlas_rect.xy + spot_lights.data[idx].atlas_rect.zw;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
- if (d < z_norm) {
+ if (d < splane.z) {
blocker_average += d;
blocker_count += 1.0;
}
@@ -792,49 +776,55 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
uv_size *= penumbra;
shadow = 0.0;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
- shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0));
+ shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, splane.z, 1.0));
}
- shadow /= float(scene_data.penumbra_shadow_samples);
+ shadow /= float(sc_penumbra_shadow_samples);
} else {
//no blockers found, so no shadow
shadow = 1.0;
}
-
} else {
-#endif
//hard shadow
- vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0);
-
+ vec3 shadow_uv = vec3(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z);
shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv);
-#ifdef USE_SOFT_SHADOWS
}
-#endif
return shadow;
}
-#endif //USE_NO_SHADOWS
+#endif // SHADOWS_DISABLED
return 1.0;
}
-void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow,
+vec2 normal_to_panorama(vec3 n) {
+ n = normalize(n);
+ vec2 panorama_coords = vec2(atan(n.x, n.z), acos(-n.y));
+
+ if (panorama_coords.x < 0.0) {
+ panorama_coords.x += M_PI * 2.0;
+ }
+
+ panorama_coords /= vec2(M_PI * 2.0, M_PI);
+ return panorama_coords;
+}
+
+void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
vec4 transmittance_color,
float transmittance_depth,
- float transmittance_curve,
float transmittance_boost,
#endif
#ifdef LIGHT_RIM_USED
- float rim, float rim_tint, vec3 rim_color,
+ float rim, float rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
float clearcoat, float clearcoat_gloss,
@@ -842,9 +832,6 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
#ifdef LIGHT_ANISOTROPY_USED
vec3 binormal, vec3 tangent, float anisotropy,
#endif
-#ifdef USE_SHADOW_TO_OPACITY
- inout float alpha,
-#endif
inout vec3 diffuse_light,
inout vec3 specular_light) {
vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
@@ -858,53 +845,71 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
vec3 color = spot_lights.data[idx].color;
float specular_amount = spot_lights.data[idx].specular_amount;
-#ifdef USE_SOFT_SHADOWS
float size_A = 0.0;
- if (spot_lights.data[idx].size > 0.0) {
+ if (sc_use_light_soft_shadows && spot_lights.data[idx].size > 0.0) {
float t = spot_lights.data[idx].size / max(0.001, light_length);
size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
}
-#endif
-
- /*
- if (spot_lights.data[idx].atlas_rect!=vec4(0.0)) {
- //use projector texture
- }
- */
#ifdef LIGHT_TRANSMITTANCE_USED
float transmittance_z = transmittance_depth;
transmittance_color.a *= light_attenuation;
{
- splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0));
+ vec4 splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0));
splane /= splane.w;
splane.xy = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy;
float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
- //reconstruct depth
- shadow_z /= spot_lights.data[idx].inv_radius;
+
+ shadow_z = shadow_z * 2.0 - 1.0;
+ float z_far = 1.0 / spot_lights.data[idx].inv_radius;
+ float z_near = 0.01;
+ shadow_z = 2.0 * z_near * z_far / (z_far + z_near - shadow_z * (z_far - z_near));
+
//distance to light plane
float z = dot(spot_dir, -light_rel_vec);
transmittance_z = z - shadow_z;
}
#endif //LIGHT_TRANSMITTANCE_USED
+ if (sc_use_light_projector && spot_lights.data[idx].projector_rect != vec4(0.0)) {
+ vec4 splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex, 1.0));
+ splane /= splane.w;
+
+ vec2 proj_uv = normal_to_panorama(splane.xyz) * spot_lights.data[idx].projector_rect.zw;
+
+ if (sc_projector_use_mipmaps) {
+ //ensure we have proper mipmaps
+ vec4 splane_ddx = (spot_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0));
+ splane_ddx /= splane_ddx.w;
+ vec2 proj_uv_ddx = normal_to_panorama(splane_ddx.xyz) * spot_lights.data[idx].projector_rect.zw - proj_uv;
+
+ vec4 splane_ddy = (spot_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0));
+ splane_ddy /= splane_ddy.w;
+ vec2 proj_uv_ddy = normal_to_panorama(splane_ddy.xyz) * spot_lights.data[idx].projector_rect.zw - proj_uv;
+
+ vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, light_projector_sampler), proj_uv + spot_lights.data[idx].projector_rect.xy, proj_uv_ddx, proj_uv_ddy);
+ color *= proj.rgb * proj.a;
+ } else {
+ vec4 proj = textureLod(sampler2D(decal_atlas_srgb, light_projector_sampler), proj_uv + spot_lights.data[idx].projector_rect.xy, 0.0);
+ color *= proj.rgb * proj.a;
+ }
+ }
light_attenuation *= shadow;
- light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
transmittance_color,
transmittance_depth,
- transmittance_curve,
transmittance_boost,
transmittance_z,
#endif
#ifdef LIGHT_RIM_USED
- rim * spot_attenuation, rim_tint, rim_color,
+ rim * spot_attenuation, rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
clearcoat, clearcoat_gloss,
@@ -912,12 +917,6 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
#ifdef LIGHT_ANISOTROPY_USED
binormal, tangent, anisotropy,
#endif
-#ifdef USE_SOFT_SHADOW
- size_A,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
diffuse_light, specular_light);
}
@@ -957,7 +956,7 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughnes
vec4 reflection;
- reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb;
+ reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb * sc_luminance_multiplier;
if (reflections.data[ref_index].exterior) {
reflection.rgb = mix(specular_light, reflection.rgb, blend);
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
index b38b8d803d..e92fbecfd0 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
@@ -7,6 +7,8 @@
/* Include our forward mobile UBOs definitions etc. */
#include "scene_forward_mobile_inc.glsl"
+#define SHADER_IS_SRGB false
+
/* INPUT ATTRIBS */
layout(location = 0) in vec3 vertex_attrib;
@@ -59,27 +61,27 @@ layout(location = 11) in vec4 weight_attrib;
/* Varyings */
-layout(location = 0) out vec3 vertex_interp;
+layout(location = 0) highp out vec3 vertex_interp;
#ifdef NORMAL_USED
-layout(location = 1) out vec3 normal_interp;
+layout(location = 1) mediump out vec3 normal_interp;
#endif
#if defined(COLOR_USED)
-layout(location = 2) out vec4 color_interp;
+layout(location = 2) mediump out vec4 color_interp;
#endif
#ifdef UV_USED
-layout(location = 3) out vec2 uv_interp;
+layout(location = 3) mediump out vec2 uv_interp;
#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
-layout(location = 4) out vec2 uv2_interp;
+layout(location = 4) mediump out vec2 uv2_interp;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 5) out vec3 tangent_interp;
-layout(location = 6) out vec3 binormal_interp;
+layout(location = 5) mediump out vec3 tangent_interp;
+layout(location = 6) mediump out vec3 binormal_interp;
#endif
#ifdef MATERIAL_UNIFORMS_USED
@@ -92,9 +94,21 @@ layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms
#ifdef MODE_DUAL_PARABOLOID
-layout(location = 8) out float dp_clip;
+layout(location = 8) out highp float dp_clip;
+
+#endif
+#ifdef USE_MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#define ViewIndex gl_ViewIndex
+#else
+// !BAS! This needs to become an input once we implement our fallback!
+#define ViewIndex 0
#endif
+#else
+// Set to zero, not supported in non stereo
+#define ViewIndex 0
+#endif //USE_MULTIVIEW
invariant gl_Position;
@@ -112,7 +126,7 @@ void main() {
mat3 world_normal_matrix;
if (bool(draw_call.flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
- world_normal_matrix = inverse(mat3(world_matrix));
+ world_normal_matrix = transpose(inverse(mat3(world_matrix)));
} else {
world_normal_matrix = mat3(world_matrix);
}
@@ -234,7 +248,13 @@ void main() {
vec4 position;
#endif
+#ifdef USE_MULTIVIEW
+ mat4 projection_matrix = scene_data.projection_matrix_view[ViewIndex];
+ mat4 inv_projection_matrix = scene_data.inv_projection_matrix_view[ViewIndex];
+#else
mat4 projection_matrix = scene_data.projection_matrix;
+ mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
+#endif //USE_MULTIVIEW
//using world coordinates
#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
@@ -352,44 +372,95 @@ void main() {
#VERSION_DEFINES
+#define SHADER_IS_SRGB false
+
+/* Specialization Constants */
+
+#if !defined(MODE_RENDER_DEPTH)
+
+#if !defined(MODE_UNSHADED)
+
+layout(constant_id = 0) const bool sc_use_light_projector = false;
+layout(constant_id = 1) const bool sc_use_light_soft_shadows = false;
+layout(constant_id = 2) const bool sc_use_directional_soft_shadows = false;
+
+layout(constant_id = 3) const uint sc_soft_shadow_samples = 4;
+layout(constant_id = 4) const uint sc_penumbra_shadow_samples = 4;
+
+layout(constant_id = 5) const uint sc_directional_soft_shadow_samples = 4;
+layout(constant_id = 6) const uint sc_directional_penumbra_shadow_samples = 4;
+
+layout(constant_id = 8) const bool sc_projector_use_mipmaps = true;
+
+layout(constant_id = 9) const bool sc_disable_omni_lights = false;
+layout(constant_id = 10) const bool sc_disable_spot_lights = false;
+layout(constant_id = 11) const bool sc_disable_reflection_probes = false;
+layout(constant_id = 12) const bool sc_disable_directional_lights = false;
+
+#endif //!MODE_UNSHADED
+
+layout(constant_id = 7) const bool sc_decal_use_mipmaps = true;
+layout(constant_id = 13) const bool sc_disable_decals = false;
+layout(constant_id = 14) const bool sc_disable_fog = false;
+
+#endif //!MODE_RENDER_DEPTH
+
+layout(constant_id = 15) const float sc_luminance_multiplier = 2.0;
+
/* Include our forward mobile UBOs definitions etc. */
#include "scene_forward_mobile_inc.glsl"
/* Varyings */
-layout(location = 0) in vec3 vertex_interp;
+layout(location = 0) highp in vec3 vertex_interp;
#ifdef NORMAL_USED
-layout(location = 1) in vec3 normal_interp;
+layout(location = 1) mediump in vec3 normal_interp;
#endif
#if defined(COLOR_USED)
-layout(location = 2) in vec4 color_interp;
+layout(location = 2) mediump in vec4 color_interp;
#endif
#ifdef UV_USED
-layout(location = 3) in vec2 uv_interp;
+layout(location = 3) mediump in vec2 uv_interp;
#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
-layout(location = 4) in vec2 uv2_interp;
+layout(location = 4) mediump in vec2 uv2_interp;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 5) in vec3 tangent_interp;
-layout(location = 6) in vec3 binormal_interp;
+layout(location = 5) mediump in vec3 tangent_interp;
+layout(location = 6) mediump in vec3 binormal_interp;
#endif
#ifdef MODE_DUAL_PARABOLOID
-layout(location = 8) in float dp_clip;
+layout(location = 8) highp in float dp_clip;
+
+#endif
+#ifdef USE_MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#define ViewIndex gl_ViewIndex
+#else
+// !BAS! This needs to become an input once we implement our fallback!
+#define ViewIndex 0
#endif
+#else
+// Set to zero, not supported in non stereo
+#define ViewIndex 0
+#endif //USE_MULTIVIEW
//defines to keep compatibility with vertex
#define world_matrix draw_call.transform
+#ifdef USE_MULTIVIEW
+#define projection_matrix scene_data.projection_matrix_view[ViewIndex]
+#else
#define projection_matrix scene_data.projection_matrix
+#endif
#if defined(ENABLE_SSS) && defined(ENABLE_TRANSMITTANCE)
//both required for transmittance to be enabled
@@ -428,7 +499,7 @@ layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness
layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter)
#else
-layout(location = 0) out vec4 frag_color;
+layout(location = 0) out mediump vec4 frag_color;
#endif // MODE_MULTIPLE_RENDER_TARGETS
#endif // RENDER DEPTH
@@ -437,6 +508,11 @@ layout(location = 0) out vec4 frag_color;
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+/* Make a default specular mode SPECULAR_SCHLICK_GGX. */
+#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) && !defined(SPECULAR_PHONG) && !defined(SPECULAR_TOON)
+#define SPECULAR_SCHLICK_GGX
+#endif
+
#include "scene_forward_lights_inc.glsl"
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
@@ -478,14 +554,14 @@ vec4 fog_process(vec3 vertex) {
}
}
- float fog_amount = 1.0 - exp(min(0.0, vertex.z * scene_data.fog_density));
+ float fog_amount = 1.0 - exp(min(0.0, -length(vertex) * scene_data.fog_density));
- if (abs(scene_data.fog_height_density) > 0.001) {
+ if (abs(scene_data.fog_height_density) >= 0.0001) {
float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y;
- float y_dist = scene_data.fog_height - y;
+ float y_dist = y - scene_data.fog_height;
- float vfog_amount = clamp(exp(y_dist * scene_data.fog_height_density), 0.0, 1.0);
+ float vfog_amount = 1.0 - exp(min(0.0, y_dist * scene_data.fog_height_density));
fog_amount = max(vfog_amount, fog_amount);
}
@@ -509,7 +585,6 @@ void main() {
vec3 backlight = vec3(0.0);
vec4 transmittance_color = vec4(0.0);
float transmittance_depth = 0.0;
- float transmittance_curve = 1.0;
float transmittance_boost = 0.0;
float metallic = 0.0;
float specular = 0.5;
@@ -622,7 +697,7 @@ void main() {
#endif
#ifdef ALPHA_ANTIALIASING_EDGE_USED
-// If alpha scissor is used, we must further the edge threshold, otherwise we wont get any edge feather
+// If alpha scissor is used, we must further the edge threshold, otherwise we won't get any edge feather
#ifdef ALPHA_SCISSOR_USED
alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0);
#endif
@@ -630,7 +705,7 @@ void main() {
#endif // ALPHA_ANTIALIASING_EDGE_USED
#ifdef USE_OPAQUE_PREPASS
- if (alpha < opaque_prepass_threshold) {
+ if (alpha < scene_data.opaque_prepass_threshold) {
discard;
}
#endif // USE_OPAQUE_PREPASS
@@ -673,7 +748,7 @@ void main() {
// to maximize VGPR usage
// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
- if (scene_data.fog_enabled) {
+ if (!sc_disable_fog && scene_data.fog_enabled) {
fog = fog_process(vertex);
}
@@ -691,7 +766,7 @@ void main() {
vec3 vertex_ddx = dFdx(vertex);
vec3 vertex_ddy = dFdy(vertex);
- { //Decals
+ if (!sc_disable_decals) { //Decals
// must implement
uint decal_indices = draw_call.decals.x;
@@ -712,25 +787,35 @@ void main() {
continue; //out of decal
}
- //we need ddx/ddy for mipmaps, so simulate them
- vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
- vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
-
float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade);
if (decals.data[decal_index].normal_fade > 0.0) {
fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5);
}
+ //we need ddx/ddy for mipmaps, so simulate them
+ vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
+ vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
+
if (decals.data[decal_index].albedo_rect != vec4(0.0)) {
//has albedo
- vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ vec4 decal_albedo;
+ if (sc_decal_use_mipmaps) {
+ decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ } else {
+ decal_albedo = textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, 0.0);
+ }
decal_albedo *= decals.data[decal_index].modulate;
decal_albedo.a *= fade;
albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix);
if (decals.data[decal_index].normal_rect != vec4(0.0)) {
- vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ vec3 decal_normal;
+ if (sc_decal_use_mipmaps) {
+ decal_normal = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ } else {
+ decal_normal = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, 0.0).xyz;
+ }
decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software
decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy)));
//convert to view space, use xzy because y is up
@@ -740,7 +825,12 @@ void main() {
}
if (decals.data[decal_index].orm_rect != vec4(0.0)) {
- vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+ vec3 decal_orm;
+ if (sc_decal_use_mipmaps) {
+ decal_orm = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+ } else {
+ decal_orm = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, 0.0).xyz;
+ }
ao = mix(ao, decal_orm.r, decal_albedo.a);
roughness = mix(roughness, decal_orm.g, decal_albedo.a);
metallic = mix(metallic, decal_orm.b, decal_albedo.a);
@@ -749,7 +839,11 @@ void main() {
if (decals.data[decal_index].emission_rect != vec4(0.0)) {
//emission is additive, so its independent from albedo
- emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ if (sc_decal_use_mipmaps) {
+ emission += textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ } else {
+ emission += textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, 0.0).xyz * decals.data[decal_index].emission_energy * fade;
+ }
}
}
} //Decals
@@ -759,9 +853,9 @@ void main() {
#ifdef NORMAL_USED
if (scene_data.roughness_limiter_enabled) {
- //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
+ //https://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
float roughness2 = roughness * roughness;
- vec3 dndu = dFdx(normal), dndv = dFdx(normal);
+ vec3 dndu = dFdx(normal), dndv = dFdy(normal);
float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv));
float kernelRoughness2 = min(2.0 * variance, scene_data.roughness_limiter_limit); //limit effect
float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2);
@@ -778,6 +872,7 @@ void main() {
if (scene_data.use_reflection_cubemap) {
vec3 ref_vec = reflect(-view, normal);
+ float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
ref_vec = scene_data.radiance_inverse_xform * ref_vec;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
@@ -790,6 +885,7 @@ void main() {
specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
+ specular_light *= horizon * horizon;
specular_light *= scene_data.ambient_light_color_energy.a;
}
@@ -838,15 +934,15 @@ void main() {
const float c4 = 0.886227;
const float c5 = 0.247708;
ambient_light += (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) +
- c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
- c4 * lightmap_captures.data[index].sh[0].rgb -
- c5 * lightmap_captures.data[index].sh[6].rgb +
- 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y +
- 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z +
- 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z +
- 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x +
- 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y +
- 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z);
+ c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
+ c4 * lightmap_captures.data[index].sh[0].rgb -
+ c5 * lightmap_captures.data[index].sh[6].rgb +
+ 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y +
+ 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z +
+ 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z +
+ 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x +
+ 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y +
+ 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z);
} else if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
bool uses_sh = bool(draw_call.flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
@@ -887,7 +983,7 @@ void main() {
// skipping ssao, do we remove ssao totally?
- { //Reflection probes
+ if (!sc_disable_reflection_probes) { //Reflection probes
vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0);
@@ -928,7 +1024,7 @@ void main() {
specular_light *= specular * metallic * albedo * 2.0;
#else
- // scales the specular reflections, needs to be be computed before lighting happens,
+ // scales the specular reflections, needs to be computed before lighting happens,
// but after environment, GI, and reflection probes are added
// Environment brdf approximation (Lazarov 2013)
// see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
@@ -953,8 +1049,8 @@ void main() {
// LIGHTING
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
- { //directional light
-
+ if (!sc_disable_directional_lights) { //directional light
+#ifndef SHADOWS_DISABLED
// Do shadow and lighting in two passes to reduce register pressure
uint shadow0 = 0;
uint shadow1 = 0;
@@ -1230,6 +1326,8 @@ void main() {
}
}
+#endif // SHADOWS_DISABLED
+
for (uint i = 0; i < 8; i++) {
if (i >= scene_data.directional_light_count) {
break;
@@ -1242,16 +1340,16 @@ void main() {
// We're not doing light transmittence
float shadow = 1.0;
-
+#ifndef SHADOWS_DISABLED
if (i < 4) {
shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0;
} else {
shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0;
}
-
+#endif
blur_shadow(shadow);
- light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0,
+ light_compute(normal, directional_lights.data[i].direction, normalize(view), 0.0, directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -1259,13 +1357,12 @@ void main() {
#ifdef LIGHT_TRANSMITTANCE_USED
transmittance_color,
transmittance_depth,
- transmittance_curve,
transmittance_boost,
transmittance_z,
#endif
*/
#ifdef LIGHT_RIM_USED
- rim, rim_tint, albedo,
+ rim, rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
clearcoat, clearcoat_gloss,
@@ -1276,15 +1373,12 @@ void main() {
#ifdef USE_SOFT_SHADOW
directional_lights.data[i].size,
#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
diffuse_light,
specular_light);
}
} //directional light
- { //omni lights
+ if (!sc_disable_omni_lights) { //omni lights
uint light_indices = draw_call.omni_lights.x;
for (uint i = 0; i < 8; i++) {
uint light_index = light_indices & 0xFF;
@@ -1298,11 +1392,11 @@ void main() {
break;
}
- float shadow = light_process_omni_shadow(light_index, vertex, view);
+ float shadow = light_process_omni_shadow(light_index, vertex, normal);
shadow = blur_shadow(shadow);
- light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow,
+ light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -1310,14 +1404,12 @@ void main() {
#ifdef LIGHT_TRANSMITTANCE_USED
transmittance_color,
transmittance_depth,
- transmittance_curve,
transmittance_boost,
#endif
*/
#ifdef LIGHT_RIM_USED
rim,
rim_tint,
- albedo,
#endif
#ifdef LIGHT_CLEARCOAT_USED
clearcoat, clearcoat_gloss,
@@ -1325,14 +1417,11 @@ void main() {
#ifdef LIGHT_ANISOTROPY_USED
tangent, binormal, anisotropy,
#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
diffuse_light, specular_light);
}
} //omni lights
- { //spot lights
+ if (!sc_disable_spot_lights) { //spot lights
uint light_indices = draw_call.spot_lights.x;
for (uint i = 0; i < 8; i++) {
@@ -1347,11 +1436,11 @@ void main() {
break;
}
- float shadow = light_process_spot_shadow(light_index, vertex, view);
+ float shadow = light_process_spot_shadow(light_index, vertex, normal);
shadow = blur_shadow(shadow);
- light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow,
+ light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -1359,14 +1448,12 @@ void main() {
#ifdef LIGHT_TRANSMITTANCE_USED
transmittance_color,
transmittance_depth,
- transmittance_curve,
transmittance_boost,
#endif
*/
#ifdef LIGHT_RIM_USED
rim,
rim_tint,
- albedo,
#endif
#ifdef LIGHT_CLEARCOAT_USED
clearcoat, clearcoat_gloss,
@@ -1374,9 +1461,6 @@ void main() {
#ifdef LIGHT_ANISOTROPY_USED
tangent, binormal, anisotropy,
#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
diffuse_light, specular_light);
}
} //spot lights
@@ -1392,7 +1476,7 @@ void main() {
#ifdef USE_OPAQUE_PREPASS
- if (alpha < opaque_prepass_threshold) {
+ if (alpha < scene_data.opaque_prepass_threshold) {
discard;
}
@@ -1464,12 +1548,15 @@ void main() {
frag_color = vec4(albedo, alpha);
#else // MODE_UNSHADED
frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha);
- //frag_color = vec4(1.0);
#endif // MODE_UNSHADED
// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+ // On mobile we use a UNORM buffer with 10bpp which results in a range from 0.0 - 1.0 resulting in HDR breaking
+ // We divide by sc_luminance_multiplier to support a range from 0.0 - 2.0 both increasing precision on bright and darker images
+ frag_color.rgb = frag_color.rgb / sc_luminance_multiplier;
+
#endif //MODE_MULTIPLE_RENDER_TARGETS
#endif //MODE_RENDER_DEPTH
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
index 0156b58574..a9a4fce82a 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
@@ -1,4 +1,9 @@
#define M_PI 3.14159265359
+#define MAX_VIEWS 2
+
+#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview)
+#extension GL_EXT_multiview : enable
+#endif
#include "decal_data_inc.glsl"
@@ -11,12 +16,12 @@
/* don't exceed 128 bytes!! */
/* put instance data into our push content, not a array */
layout(push_constant, binding = 0, std430) uniform DrawCall {
- mat4 transform; // 64 - 64
+ highp mat4 transform; // 64 - 64
uint flags; // 04 - 68
uint instance_uniforms_ofs; //base offset in global buffer for instance variables // 04 - 72
uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) // 04 - 76
uint layer_mask; // 04 - 80
- vec4 lightmap_uv_scale; // 16 - 96 doubles as uv_offset when needed
+ highp vec4 lightmap_uv_scale; // 16 - 96 doubles as uv_offset when needed
uvec2 reflection_probes; // 08 - 104
uvec2 omni_lights; // 08 - 112
@@ -46,12 +51,16 @@ layout(set = 0, binding = 1) uniform sampler material_samplers[12];
layout(set = 0, binding = 2) uniform sampler shadow_sampler;
+layout(set = 0, binding = 3) uniform sampler decal_sampler;
+layout(set = 0, binding = 4) uniform sampler light_projector_sampler;
+
+#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 5)
#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6)
#define INSTANCE_FLAGS_USE_SDFGI (1 << 7)
#define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 8)
#define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 9)
#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 10)
-#define INSTANCE_FLAGS_USE_GIPROBE (1 << 11)
+#define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 11)
#define INSTANCE_FLAGS_MULTIMESH (1 << 12)
#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13)
#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14)
@@ -60,24 +69,22 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler;
//3 bits of stride
#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF
-#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 24)
-
-layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
+layout(set = 0, binding = 5, std430) restrict readonly buffer OmniLights {
LightData data[];
}
omni_lights;
-layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
+layout(set = 0, binding = 6, std430) restrict readonly buffer SpotLights {
LightData data[];
}
spot_lights;
-layout(set = 0, binding = 5, std430) restrict readonly buffer ReflectionProbeData {
+layout(set = 0, binding = 7, std430) restrict readonly buffer ReflectionProbeData {
ReflectionData data[];
}
reflections;
-layout(set = 0, binding = 6, std140) uniform DirectionalLights {
+layout(set = 0, binding = 8, std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
directional_lights;
@@ -86,100 +93,97 @@ directional_lights;
#define LIGHTMAP_FLAG_USE_SPECULAR_DIRECTION 2
struct Lightmap {
- mat3 normal_xform;
+ mediump mat3 normal_xform;
};
-layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
+layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps {
Lightmap data[];
}
lightmaps;
struct LightmapCapture {
- vec4 sh[9];
+ mediump vec4 sh[9];
};
-layout(set = 0, binding = 8, std140) restrict readonly buffer LightmapCaptures {
+layout(set = 0, binding = 10, std140) restrict readonly buffer LightmapCaptures {
LightmapCapture data[];
}
lightmap_captures;
-layout(set = 0, binding = 9) uniform texture2D decal_atlas;
-layout(set = 0, binding = 10) uniform texture2D decal_atlas_srgb;
+layout(set = 0, binding = 11) uniform mediump texture2D decal_atlas;
+layout(set = 0, binding = 12) uniform mediump texture2D decal_atlas_srgb;
-layout(set = 0, binding = 11, std430) restrict readonly buffer Decals {
+layout(set = 0, binding = 13, std430) restrict readonly buffer Decals {
DecalData data[];
}
decals;
-layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableData {
- vec4 data[];
+layout(set = 0, binding = 14, std430) restrict readonly buffer GlobalVariableData {
+ highp vec4 data[];
}
global_variables;
/* Set 1: Render Pass (changes per render pass) */
layout(set = 1, binding = 0, std140) uniform SceneData {
- mat4 projection_matrix;
- mat4 inv_projection_matrix;
-
- mat4 camera_matrix;
- mat4 inv_camera_matrix;
+ highp mat4 projection_matrix;
+ highp mat4 inv_projection_matrix;
+ highp mat4 camera_matrix;
+ highp mat4 inv_camera_matrix;
- vec2 viewport_size;
- vec2 screen_pixel_size;
+ // only used for multiview
+ highp mat4 projection_matrix_view[MAX_VIEWS];
+ highp mat4 inv_projection_matrix_view[MAX_VIEWS];
- //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];
+ highp vec2 viewport_size;
+ highp vec2 screen_pixel_size;
- uint directional_penumbra_shadow_samples;
- uint directional_soft_shadow_samples;
- uint penumbra_shadow_samples;
- uint soft_shadow_samples;
+ // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted.
+ highp vec4 directional_penumbra_shadow_kernel[32];
+ highp vec4 directional_soft_shadow_kernel[32];
+ highp vec4 penumbra_shadow_kernel[32];
+ highp vec4 soft_shadow_kernel[32];
- vec4 ambient_light_color_energy;
+ mediump vec4 ambient_light_color_energy;
- float ambient_color_sky_mix;
+ mediump float ambient_color_sky_mix;
bool use_ambient_light;
bool use_ambient_cubemap;
bool use_reflection_cubemap;
- mat3 radiance_inverse_xform;
+ mediump mat3 radiance_inverse_xform;
- vec2 shadow_atlas_pixel_size;
- vec2 directional_shadow_pixel_size;
+ highp vec2 shadow_atlas_pixel_size;
+ highp vec2 directional_shadow_pixel_size;
uint directional_light_count;
- float dual_paraboloid_side;
- float z_far;
- float z_near;
+ mediump float dual_paraboloid_side;
+ highp float z_far;
+ highp float z_near;
bool ssao_enabled;
- float ssao_light_affect;
- float ssao_ao_affect;
+ mediump float ssao_light_affect;
+ mediump float ssao_ao_affect;
bool roughness_limiter_enabled;
- float roughness_limiter_amount;
- float roughness_limiter_limit;
- uvec2 roughness_limiter_pad;
-
- vec4 ao_color;
+ mediump float roughness_limiter_amount;
+ mediump float roughness_limiter_limit;
+ mediump float opaque_prepass_threshold;
+ uint roughness_limiter_pad;
bool fog_enabled;
- float fog_density;
- float fog_height;
- float fog_height_density;
+ highp float fog_density;
+ highp float fog_height;
+ highp float fog_height_density;
- vec3 fog_light_color;
- float fog_sun_scatter;
+ mediump vec3 fog_light_color;
+ mediump float fog_sun_scatter;
- float fog_aerial_perspective;
+ mediump float fog_aerial_perspective;
bool material_uv2_mode;
- float time;
- float reflection_multiplier; // one normally, zero when rendering reflections
+ highp float time;
+ mediump float reflection_multiplier; // one normally, zero when rendering reflections
bool pancake_shadows;
uint pad1;
@@ -190,30 +194,30 @@ scene_data;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
-layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap;
+layout(set = 1, binding = 2) uniform mediump textureCubeArray radiance_cubemap;
#else
-layout(set = 1, binding = 2) uniform textureCube radiance_cubemap;
+layout(set = 1, binding = 2) uniform mediump textureCube radiance_cubemap;
#endif
-layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas;
+layout(set = 1, binding = 3) uniform mediump textureCubeArray reflection_atlas;
-layout(set = 1, binding = 4) uniform texture2D shadow_atlas;
+layout(set = 1, binding = 4) uniform highp texture2D shadow_atlas;
-layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas;
+layout(set = 1, binding = 5) uniform highp texture2D directional_shadow_atlas;
// this needs to change to providing just the lightmap we're using..
layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
-layout(set = 1, binding = 9) uniform texture2D depth_buffer;
-layout(set = 1, binding = 10) uniform texture2D color_buffer;
+layout(set = 1, binding = 9) uniform highp texture2D depth_buffer;
+layout(set = 1, binding = 10) uniform mediump texture2D color_buffer;
/* Set 2 Skeleton & Instancing (can change per item) */
layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms {
- vec4 data[];
+ highp vec4 data[];
}
transforms;
diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl
index 7e06516d90..2328effe7b 100644
--- a/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl
+++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl
@@ -36,12 +36,12 @@ void main() {
float divisor = 0.0;
vec4 color;
float depth;
- vec3 normal;
+ vec4 normal;
if (params.filtered) {
color = vec4(0.0);
depth = 0.0;
- normal = vec3(0.0);
+ normal = vec4(0.0);
for (int i = 0; i < 4; i++) {
ivec2 ofs = ssC << 1;
@@ -53,7 +53,9 @@ void main() {
}
color += texelFetch(source_ssr, ofs, 0);
float d = texelFetch(source_depth, ofs, 0).r;
- normal += texelFetch(source_normal, ofs, 0).xyz * 2.0 - 1.0;
+ vec4 nr = texelFetch(source_normal, ofs, 0);
+ normal.xyz += nr.xyz * 2.0 - 1.0;
+ normal.w += nr.w;
d = d * 2.0 - 1.0;
if (params.orthogonal) {
@@ -66,11 +68,12 @@ void main() {
color /= 4.0;
depth /= 4.0;
- normal = normalize(normal / 4.0) * 0.5 + 0.5;
+ normal.xyz = normalize(normal.xyz / 4.0) * 0.5 + 0.5;
+ normal.w /= 4.0;
} else {
color = texelFetch(source_ssr, ssC << 1, 0);
depth = texelFetch(source_depth, ssC << 1, 0).r;
- normal = texelFetch(source_normal, ssC << 1, 0).xyz;
+ normal = texelFetch(source_normal, ssC << 1, 0);
depth = depth * 2.0 - 1.0;
if (params.orthogonal) {
@@ -83,5 +86,5 @@ void main() {
imageStore(dest_ssr, ssC, color);
imageStore(dest_depth, ssC, vec4(depth));
- imageStore(dest_normal, ssC, vec4(normal, 0.0));
+ imageStore(dest_normal, ssC, normal);
}
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
index 0eacbc5363..4290d5b869 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
@@ -24,7 +24,7 @@ layout(push_constant, binding = 0, std430) uniform Params {
}
params;
-// http://in4k.untergrund.net/html_articles/hugi_27_-_coding_corner_polaris_sphere_tessellation_101.htm
+// https://in4k.untergrund.net/html_articles/hugi_27_-_coding_corner_polaris_sphere_tessellation_101.htm
vec3 get_sphere_vertex(uint p_vertex_id) {
float x_angle = float(p_vertex_id & 1u) + (p_vertex_id >> params.band_power);
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
index 99db35bb34..d6e5c6a92e 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
@@ -20,10 +20,10 @@ layout(set = 0, binding = 3, std430) restrict readonly buffer DispatchData {
dispatch_data;
struct ProcessVoxel {
- uint position; //xyz 7 bit packed, extra 11 bits for neigbours
- uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours
- uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours
- uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours
+ uint position; // xyz 7 bit packed, extra 11 bits for neighbors.
+ uint albedo; // rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neighbors.
+ uint light; // rgbe8985 encoded total saved light, extra 2 bits for neighbors.
+ uint light_aniso; // 55555 light anisotropy, extra 2 bits for neighbors.
//total neighbours: 26
};
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
index bc376e9522..eedd28959c 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
@@ -266,9 +266,9 @@ void main() {
} else if (params.sky_mode == SKY_MODE_SKY) {
#ifdef USE_CUBEMAP_ARRAY
- light.rgb = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(ray_dir, 0.0), 2.0).rgb; //use second mipmap because we dont usually throw a lot of rays, so this compensates
+ light.rgb = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(ray_dir, 0.0), 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates.
#else
- light.rgb = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), ray_dir, 2.0).rgb; //use second mipmap because we dont usually throw a lot of rays, so this compensates
+ light.rgb = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), ray_dir, 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates.
#endif
light.rgb *= params.sky_energy;
light.a = 0.0;
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
index aa4ded146f..4d9fa85a74 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
@@ -101,7 +101,7 @@ layout(set = 0, binding = 10, std430) restrict buffer DispatchData {
dispatch_data;
struct ProcessVoxel {
- uint position; //xyz 7 bit packed, extra 11 bits for neigbours
+ uint position; // xyz 7 bit packed, extra 11 bits for neighbors.
uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours
uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours
uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours
@@ -134,7 +134,7 @@ layout(set = 0, binding = 5, std430) restrict buffer readonly DispatchData {
dispatch_data;
struct ProcessVoxel {
- uint position; //xyz 7 bit packed, extra 11 bits for neigbours
+ uint position; // xyz 7 bit packed, extra 11 bits for neighbors.
uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours
uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours
uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours
@@ -183,7 +183,7 @@ void main() {
ivec3 write_pos = read_pos + params.scroll;
if (any(lessThan(write_pos, ivec3(0))) || any(greaterThanEqual(write_pos, ivec3(params.grid_size)))) {
- return; //fits outside the 3D texture, dont do anything
+ return; // Fits outside the 3D texture, don't do anything.
}
uint albedo = ((src_process_voxels.data[index].albedo & 0x7FFF) << 1) | 1; //add solid bit
diff --git a/servers/rendering/renderer_rd/shaders/sky.glsl b/servers/rendering/renderer_rd/shaders/sky.glsl
index 9924da37d5..d07a454ade 100644
--- a/servers/rendering/renderer_rd/shaders/sky.glsl
+++ b/servers/rendering/renderer_rd/shaders/sky.glsl
@@ -4,13 +4,21 @@
#VERSION_DEFINES
+#define MAX_VIEWS 2
+
+#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview)
+#extension GL_EXT_multiview : enable
+#endif
+
layout(location = 0) out vec2 uv_interp;
layout(push_constant, binding = 1, std430) uniform Params {
mat3 orientation;
- vec4 proj;
+ vec4 projections[MAX_VIEWS];
vec4 position_multiplier;
float time;
+ float luminance_multiplier;
+ float pad[2];
}
params;
@@ -26,15 +34,31 @@ void main() {
#VERSION_DEFINES
+#ifdef USE_MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#extension GL_EXT_multiview : enable
+#define ViewIndex gl_ViewIndex
+#else // has_VK_KHR_multiview
+// !BAS! This needs to become an input once we implement our fallback!
+#define ViewIndex 0
+#endif // has_VK_KHR_multiview
+#else // USE_MULTIVIEW
+// Set to zero, not supported in non stereo
+#define ViewIndex 0
+#endif //USE_MULTIVIEW
+
#define M_PI 3.14159265359
+#define MAX_VIEWS 2
layout(location = 0) in vec2 uv_interp;
layout(push_constant, binding = 1, std430) uniform Params {
mat3 orientation;
- vec4 proj;
+ vec4 projections[MAX_VIEWS];
vec4 position_multiplier;
- float time; //TODO consider adding vec2 screen res, and float radiance size
+ float time;
+ float luminance_multiplier;
+ float pad[2];
}
params;
@@ -85,7 +109,6 @@ struct DirectionalLightData {
layout(set = 0, binding = 3, std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
-
directional_lights;
#ifdef MATERIAL_UNIFORMS_USED
@@ -154,8 +177,8 @@ vec4 fog_process(vec3 view, vec3 sky_color) {
void main() {
vec3 cube_normal;
cube_normal.z = -1.0;
- cube_normal.x = (cube_normal.z * (-uv_interp.x - params.proj.x)) / params.proj.y;
- cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.proj.z)) / params.proj.w;
+ cube_normal.x = (cube_normal.z * (-uv_interp.x - params.projections[ViewIndex].x)) / params.projections[ViewIndex].y;
+ cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.projections[ViewIndex].z)) / params.projections[ViewIndex].w;
cube_normal = mat3(params.orientation) * cube_normal;
cube_normal.z = -cube_normal.z;
cube_normal = normalize(cube_normal);
@@ -180,17 +203,17 @@ void main() {
vec3 inverted_cube_normal = cube_normal;
inverted_cube_normal.z *= -1.0;
#ifdef USES_HALF_RES_COLOR
- half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal);
+ half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal) * params.luminance_multiplier;
#endif
#ifdef USES_QUARTER_RES_COLOR
- quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal);
+ quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal) * params.luminance_multiplier;
#endif
#else
#ifdef USES_HALF_RES_COLOR
- half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
+ half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * params.luminance_multiplier;
#endif
#ifdef USES_QUARTER_RES_COLOR
- quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
+ quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * params.luminance_multiplier;
#endif
#endif
@@ -227,4 +250,7 @@ void main() {
if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) {
frag_color.a = 0.0;
}
+
+ // For mobile renderer we're dividing by 2.0 as we're using a UNORM buffer
+ frag_color.rgb = frag_color.rgb / params.luminance_multiplier;
}
diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl
index 86b4da6b08..948c6e1e39 100644
--- a/servers/rendering/renderer_rd/shaders/tonemap.glsl
+++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl
@@ -4,6 +4,12 @@
#VERSION_DEFINES
+#ifdef MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#extension GL_EXT_multiview : enable
+#endif
+#endif
+
layout(location = 0) out vec2 uv_interp;
void main() {
@@ -18,11 +24,28 @@ void main() {
#VERSION_DEFINES
+#ifdef MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#extension GL_EXT_multiview : enable
+#define ViewIndex gl_ViewIndex
+#else // has_VK_KHR_multiview
+#define ViewIndex 0
+#endif // has_VK_KHR_multiview
+#endif //MULTIVIEW
+
layout(location = 0) in vec2 uv_interp;
+#ifdef SUBPASS
+layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput input_color;
+#elif defined(MULTIVIEW)
+layout(set = 0, binding = 0) uniform sampler2DArray source_color;
+#else
layout(set = 0, binding = 0) uniform sampler2D source_color;
+#endif
+
layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
layout(set = 2, binding = 0) uniform sampler2D source_glow;
+
#ifdef USE_1D_LUT
layout(set = 3, binding = 0) uniform sampler2D source_color_correction;
#else
@@ -48,7 +71,7 @@ layout(push_constant, binding = 1, std430) uniform Params {
float exposure;
float white;
float auto_exposure_grey;
- uint pad2;
+ float luminance_multiplier;
vec2 pixel_size;
bool use_fxaa;
@@ -117,7 +140,7 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) {
vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5f)) * pixel_size;
return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) +
- (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod)));
+ (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod)));
}
#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod)
@@ -146,25 +169,38 @@ vec3 tonemap_filmic(vec3 color, float white) {
return color_tonemapped / white_tonemapped;
}
+// Adapted from https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
+// (MIT License).
vec3 tonemap_aces(vec3 color, float white) {
- const float exposure_bias = 0.85f;
- const float A = 2.51f * exposure_bias * exposure_bias;
- const float B = 0.03f * exposure_bias;
- const float C = 2.43f * exposure_bias * exposure_bias;
- const float D = 0.59f * exposure_bias;
- const float E = 0.14f;
-
- vec3 color_tonemapped = (color * (A * color + B)) / (color * (C * color + D) + E);
- float white_tonemapped = (white * (A * white + B)) / (white * (C * white + D) + E);
+ const float exposure_bias = 1.8f;
+ const float A = 0.0245786f;
+ const float B = 0.000090537f;
+ const float C = 0.983729f;
+ const float D = 0.432951f;
+ const float E = 0.238081f;
+
+ // Exposure bias baked into transform to save shader instructions. Equivalent to `color *= exposure_bias`
+ const mat3 rgb_to_rrt = mat3(
+ vec3(0.59719f * exposure_bias, 0.35458f * exposure_bias, 0.04823f * exposure_bias),
+ vec3(0.07600f * exposure_bias, 0.90834f * exposure_bias, 0.01566f * exposure_bias),
+ vec3(0.02840f * exposure_bias, 0.13383f * exposure_bias, 0.83777f * exposure_bias));
+
+ const mat3 odt_to_rgb = mat3(
+ vec3(1.60475f, -0.53108f, -0.07367f),
+ vec3(-0.10208f, 1.10813f, -0.00605f),
+ vec3(-0.00327f, -0.07276f, 1.07602f));
+
+ color *= rgb_to_rrt;
+ vec3 color_tonemapped = (color * (color + A) - B) / (color * (C * color + D) + E);
+ color_tonemapped *= odt_to_rgb;
+
+ white *= exposure_bias;
+ float white_tonemapped = (white * (white + A) - B) / (white * (C * white + D) + E);
return color_tonemapped / white_tonemapped;
}
vec3 tonemap_reinhard(vec3 color, float white) {
- // Ensure color values are positive.
- // They can be negative in the case of negative lights, which leads to undesired behavior.
- color = max(vec3(0.0), color);
-
return (white * color + color) / (color * white + white);
}
@@ -181,15 +217,16 @@ vec3 linear_to_srgb(vec3 color) {
#define TONEMAPPER_ACES 3
vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always outputs clamped [0;1] color
-
+ // Ensure color values passed to tonemappers are positive.
+ // They can be negative in the case of negative lights, which leads to undesired behavior.
if (params.tonemapper == TONEMAPPER_LINEAR) {
return color;
} else if (params.tonemapper == TONEMAPPER_REINHARD) {
- return tonemap_reinhard(color, white);
+ return tonemap_reinhard(max(vec3(0.0f), color), white);
} else if (params.tonemapper == TONEMAPPER_FILMIC) {
- return tonemap_filmic(color, white);
- } else { //aces
- return tonemap_aces(color, white);
+ return tonemap_filmic(max(vec3(0.0f), color), white);
+ } else { // TONEMAPPER_ACES
+ return tonemap_aces(max(vec3(0.0f), color), white);
}
}
@@ -272,15 +309,23 @@ vec3 apply_color_correction(vec3 color) {
}
#endif
+#ifndef SUBPASS
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;
+#ifdef MULTIVIEW
+ vec3 rgbNW = textureLod(source_color, vec3(uv_interp + vec2(-1.0, -1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier;
+ vec3 rgbNE = textureLod(source_color, vec3(uv_interp + vec2(1.0, -1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier;
+ vec3 rgbSW = textureLod(source_color, vec3(uv_interp + vec2(-1.0, 1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier;
+ vec3 rgbSE = textureLod(source_color, vec3(uv_interp + vec2(1.0, 1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier;
+#else
+ vec3 rgbNW = textureLod(source_color, uv_interp + vec2(-1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier;
+ vec3 rgbNE = textureLod(source_color, uv_interp + vec2(1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier;
+ vec3 rgbSW = textureLod(source_color, uv_interp + vec2(-1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier;
+ vec3 rgbSE = textureLod(source_color, uv_interp + vec2(1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier;
+#endif
vec3 rgbM = color;
vec3 luma = vec3(0.299, 0.587, 0.114);
float lumaNW = dot(rgbNW, luma);
@@ -296,17 +341,22 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *
- (0.25 * FXAA_REDUCE_MUL),
+ (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;
+ params.pixel_size;
- vec3 rgbA = 0.5 * exposure * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz);
- vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz);
+#ifdef MULTIVIEW
+ vec3 rgbA = 0.5 * exposure * (textureLod(source_color, vec3(uv_interp + dir * (1.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * (2.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz) * params.luminance_multiplier;
+ vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, vec3(uv_interp + dir * -0.5, ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * 0.5, ViewIndex), 0.0).xyz) * params.luminance_multiplier;
+#else
+ vec3 rgbA = 0.5 * exposure * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz) * params.luminance_multiplier;
+ vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz) * params.luminance_multiplier;
+#endif
float lumaB = dot(rgbB, luma);
if ((lumaB < lumaMin) || (lumaB > lumaMax)) {
@@ -315,8 +365,9 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
return rgbB;
}
}
+#endif // !SUBPASS
-// From http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
+// From https://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom)
// NOTE: `frag_coord` is in pixels (i.e. not normalized UV).
vec3 screen_space_dither(vec2 frag_coord) {
@@ -329,41 +380,54 @@ vec3 screen_space_dither(vec2 frag_coord) {
}
void main() {
- vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb;
+#ifdef SUBPASS
+ // SUBPASS and MULTIVIEW can be combined but in that case we're already reading from the correct layer
+ vec3 color = subpassLoad(input_color).rgb * params.luminance_multiplier;
+#elif defined(MULTIVIEW)
+ vec3 color = textureLod(source_color, vec3(uv_interp, ViewIndex), 0.0f).rgb * params.luminance_multiplier;
+#else
+ vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb * params.luminance_multiplier;
+#endif
// Exposure
float exposure = params.exposure;
+#ifndef SUBPASS
if (params.use_auto_exposure) {
- exposure *= 1.0 / (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.luminance_multiplier / params.auto_exposure_grey);
}
+#endif
color *= exposure;
// Early Tonemap & SRGB Conversion
-
+#ifndef SUBPASS
if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) {
- vec3 glow = gather_glow(source_glow, uv_interp);
+ vec3 glow = gather_glow(source_glow, uv_interp) * params.luminance_multiplier;
color.rgb = mix(color.rgb, glow, params.glow_intensity);
}
if (params.use_fxaa) {
color = do_fxaa(color, exposure, uv_interp);
}
+#endif
+
if (params.use_debanding) {
// For best results, debanding should be done before tonemapping.
// Otherwise, we're adding noise to an already-quantized image.
color += screen_space_dither(gl_FragCoord.xy);
}
+
color = apply_tonemapping(color, params.white);
color = linear_to_srgb(color); // regular linear -> SRGB conversion
+#ifndef SUBPASS
// Glow
if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) {
- vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity;
+ vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity * params.luminance_multiplier;
// high dynamic range -> SRGB
glow = apply_tonemapping(glow, params.white);
@@ -371,6 +435,7 @@ void main() {
color = apply_glow(color, glow);
}
+#endif
// Additional effects
diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
index c793b6ebe1..181d3b272f 100644
--- a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
+++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
@@ -4,219 +4,103 @@
#VERSION_DEFINES
-/* Do not use subgroups here, seems there is not much advantage and causes glitches
-#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic)
-#extension GL_KHR_shader_subgroup_ballot: enable
-#extension GL_KHR_shader_subgroup_arithmetic: enable
-
-#define USE_SUBGROUPS
-#endif
-*/
-
-#if defined(MODE_FOG) || defined(MODE_FILTER)
-
-layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
-
-#endif
-
-#if defined(MODE_DENSITY)
-
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
-#endif
+#define SAMPLER_NEAREST_CLAMP 0
+#define SAMPLER_LINEAR_CLAMP 1
+#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
+#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3
+#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4
+#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5
+#define SAMPLER_NEAREST_REPEAT 6
+#define SAMPLER_LINEAR_REPEAT 7
+#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8
+#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9
+#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
+#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
+
+#define DENSITY_SCALE 1024.0
#include "cluster_data_inc.glsl"
#include "light_data_inc.glsl"
#define M_PI 3.14159265359
-layout(set = 0, binding = 1) uniform texture2D shadow_atlas;
-layout(set = 0, binding = 2) uniform texture2D directional_shadow_atlas;
-
-layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
- LightData data[];
-}
-omni_lights;
-
-layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
- LightData data[];
-}
-spot_lights;
+layout(set = 0, binding = 1) uniform sampler material_samplers[12];
-layout(set = 0, binding = 5, std140) uniform DirectionalLights {
- DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+layout(set = 0, binding = 2, std430) restrict readonly buffer GlobalVariableData {
+ vec4 data[];
}
-directional_lights;
-
-layout(set = 0, binding = 6, std430) buffer restrict readonly ClusterBuffer {
- uint data[];
-}
-cluster_buffer;
-
-layout(set = 0, binding = 7) uniform sampler linear_sampler;
-
-#ifdef MODE_DENSITY
-layout(rgba16f, set = 0, binding = 8) uniform restrict writeonly image3D density_map;
-layout(rgba16f, set = 0, binding = 9) uniform restrict readonly image3D fog_map; //unused
-#endif
-
-#ifdef MODE_FOG
-layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D density_map;
-layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D fog_map;
-#endif
-
-#ifdef MODE_FILTER
-layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map;
-layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map;
-#endif
-
-layout(set = 0, binding = 10) uniform sampler shadow_sampler;
-
-#define MAX_GI_PROBES 8
-
-struct GIProbeData {
- mat4 xform;
- vec3 bounds;
- float dynamic_range;
+global_variables;
- float bias;
- float normal_bias;
- bool blend_ambient;
- uint texture_slot;
-
- float anisotropy_strength;
- float ambient_occlusion;
- float ambient_occlusion_size;
- uint mipmaps;
-};
-
-layout(set = 0, binding = 11, std140) uniform GIProbes {
- GIProbeData data[MAX_GI_PROBES];
-}
-gi_probes;
-
-layout(set = 0, binding = 12) uniform texture3D gi_probe_textures[MAX_GI_PROBES];
-
-layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps;
-
-#ifdef ENABLE_SDFGI
-
-// SDFGI Integration on set 1
-#define SDFGI_MAX_CASCADES 8
-
-struct SDFGIProbeCascadeData {
+layout(push_constant, binding = 0, std430) uniform Params {
vec3 position;
- float to_probe;
- ivec3 probe_world_offset;
- float to_cell; // 1/bounds * grid_size
-};
-
-layout(set = 1, binding = 0, std140) uniform SDFGI {
- vec3 grid_size;
- uint max_cascades;
-
- bool use_occlusion;
- int probe_axis_size;
- float probe_to_uvw;
- float normal_bias;
+ float pad;
- vec3 lightprobe_tex_pixel_size;
- float energy;
+ vec3 extents;
+ float pad2;
- vec3 lightprobe_uv_offset;
- float y_mult;
+ ivec3 corner;
+ uint shape;
- vec3 occlusion_clamp;
- uint pad3;
-
- vec3 occlusion_renormalize;
- uint pad4;
-
- vec3 cascade_probe_size;
- uint pad5;
-
- SDFGIProbeCascadeData cascades[SDFGI_MAX_CASCADES];
+ mat4 transform;
}
-sdfgi;
-
-layout(set = 1, binding = 1) uniform texture2DArray sdfgi_ambient_texture;
-
-layout(set = 1, binding = 2) uniform texture3D sdfgi_occlusion_texture;
+params;
-#endif //SDFGI
+#ifdef MOLTENVK_USED
+layout(set = 1, binding = 1) volatile buffer emissive_only_map_buffer {
+ uint emissive_only_map[];
+};
+#else
+layout(r32ui, set = 1, binding = 1) uniform volatile uimage3D emissive_only_map;
+#endif
-layout(set = 0, binding = 14, std140) uniform Params {
+layout(set = 1, binding = 2, std140) uniform SceneParams {
vec2 fog_frustum_size_begin;
vec2 fog_frustum_size_end;
float fog_frustum_end;
- float z_near;
- float z_far;
- int filter_axis;
+ float z_near; //
+ float z_far; //
+ float time;
ivec3 fog_volume_size;
- uint directional_light_count;
-
- vec3 light_color;
- float base_density;
-
- float detail_spread;
- float gi_inject;
- uint max_gi_probes;
- uint cluster_type_size;
+ uint directional_light_count; //
- vec2 screen_size;
- uint cluster_shift;
- uint cluster_width;
-
- uint max_cluster_element_count_div_32;
bool use_temporal_reprojection;
uint temporal_frame;
+ float detail_spread;
float temporal_blend;
- mat3x4 cam_rotation;
mat4 to_prev_view;
+ mat4 transform;
}
-params;
-
-layout(set = 0, binding = 15) uniform texture3D prev_density_texture;
+scene_params;
-float get_depth_at_pos(float cell_depth_size, int z) {
- float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels
- d = pow(d, params.detail_spread);
- return params.fog_frustum_end * d;
-}
-
-vec3 hash3f(uvec3 x) {
- x = ((x >> 16) ^ x) * 0x45d9f3b;
- x = ((x >> 16) ^ x) * 0x45d9f3b;
- x = (x >> 16) ^ x;
- return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF));
-}
-
-float get_omni_attenuation(float distance, float inv_range, float decay) {
- float nd = distance * inv_range;
- nd *= nd;
- nd *= nd; // nd^4
- nd = max(1.0 - nd, 0.0);
- nd *= nd; // nd^2
- return nd * pow(max(distance, 0.0001), -decay);
-}
+#ifdef MOLTENVK_USED
+layout(set = 1, binding = 3) volatile buffer density_only_map_buffer {
+ uint density_only_map[];
+};
+layout(set = 1, binding = 4) volatile buffer light_only_map_buffer {
+ uint light_only_map[];
+};
+#else
+layout(r32ui, set = 1, binding = 3) uniform volatile uimage3D density_only_map;
+layout(r32ui, set = 1, binding = 4) uniform volatile uimage3D light_only_map;
+#endif
-void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) {
- uint item_min_max = cluster_buffer.data[p_offset];
- item_min = item_min_max & 0xFFFF;
- item_max = item_min_max >> 16;
- ;
+#ifdef MATERIAL_UNIFORMS_USED
+layout(set = 2, binding = 0, std140) uniform MaterialUniforms{
+#MATERIAL_UNIFORMS
+} material;
+#endif
- item_from = item_min >> 5;
- item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements
-}
+#GLOBALS
-uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) {
- int local_min = clamp(int(z_min) - int(i) * 32, 0, 31);
- int mask_width = min(int(z_max) - int(z_min), 32 - local_min);
- return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width);
+float get_depth_at_pos(float cell_depth_size, int z) {
+ float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels
+ d = pow(d, scene_params.detail_spread);
+ return scene_params.fog_frustum_end * d;
}
#define TEMPORAL_FRAMES 16
@@ -240,464 +124,167 @@ const vec3 halton_map[TEMPORAL_FRAMES] = vec3[](
vec3(0.03125, 0.59259259, 0.32));
void main() {
- vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size);
+ vec3 fog_cell_size = 1.0 / vec3(scene_params.fog_volume_size);
-#ifdef MODE_DENSITY
-
- ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
- if (any(greaterThanEqual(pos, params.fog_volume_size))) {
+ ivec3 pos = ivec3(gl_GlobalInvocationID.xyz) + params.corner;
+ if (any(greaterThanEqual(pos, scene_params.fog_volume_size))) {
return; //do not compute
}
+#ifdef MOLTENVK_USED
+ uint lpos = pos.z * scene_params.fog_volume_size.x * scene_params.fog_volume_size.y + pos.y * scene_params.fog_volume_size.x + pos.x;
+#endif
vec3 posf = vec3(pos);
- //posf += mix(vec3(0.0),vec3(1.0),0.3) * hash3f(uvec3(pos)) * 2.0 - 1.0;
-
vec3 fog_unit_pos = posf * fog_cell_size + fog_cell_size * 0.5; //center of voxels
-
- uvec2 screen_pos = uvec2(fog_unit_pos.xy * params.screen_size);
- uvec2 cluster_pos = screen_pos >> params.cluster_shift;
- uint cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32);
- //positions in screen are too spread apart, no hopes for optimizing with subgroups
-
- fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread);
+ fog_unit_pos.z = pow(fog_unit_pos.z, scene_params.detail_spread);
vec3 view_pos;
- view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z));
- view_pos.z = -params.fog_frustum_end * fog_unit_pos.z;
+ view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(fog_unit_pos.z));
+ view_pos.z = -scene_params.fog_frustum_end * fog_unit_pos.z;
view_pos.y = -view_pos.y;
- vec4 reprojected_density = vec4(0.0);
- float reproject_amount = 0.0;
-
- if (params.use_temporal_reprojection) {
- vec3 prev_view = (params.to_prev_view * vec4(view_pos, 1.0)).xyz;
+ if (scene_params.use_temporal_reprojection) {
+ vec3 prev_view = (scene_params.to_prev_view * vec4(view_pos, 1.0)).xyz;
//undo transform into prev view
prev_view.y = -prev_view.y;
//z back to unit size
- prev_view.z /= -params.fog_frustum_end;
+ prev_view.z /= -scene_params.fog_frustum_end;
//xy back to unit size
- prev_view.xy /= mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(prev_view.z));
+ prev_view.xy /= mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(prev_view.z));
prev_view.xy = prev_view.xy * 0.5 + 0.5;
//z back to unspread value
- prev_view.z = pow(prev_view.z, 1.0 / params.detail_spread);
+ prev_view.z = pow(prev_view.z, 1.0 / scene_params.detail_spread);
if (all(greaterThan(prev_view, vec3(0.0))) && all(lessThan(prev_view, vec3(1.0)))) {
//reprojectinon fits
-
- reprojected_density = textureLod(sampler3D(prev_density_texture, linear_sampler), prev_view, 0.0);
- reproject_amount = params.temporal_blend;
-
// Since we can reproject, now we must jitter the current view pos.
// This is done here because cells that can't reproject should not jitter.
- fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[params.temporal_frame]; //center of voxels, offset by halton table
-
- screen_pos = uvec2(fog_unit_pos.xy * params.screen_size);
- cluster_pos = screen_pos >> params.cluster_shift;
- cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32);
- //positions in screen are too spread apart, no hopes for optimizing with subgroups
+ fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[scene_params.temporal_frame]; //center of voxels, offset by halton table
+ fog_unit_pos.z = pow(fog_unit_pos.z, scene_params.detail_spread);
- fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread);
-
- view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z));
- view_pos.z = -params.fog_frustum_end * fog_unit_pos.z;
+ view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(fog_unit_pos.z));
+ view_pos.z = -scene_params.fog_frustum_end * fog_unit_pos.z;
view_pos.y = -view_pos.y;
}
}
- uint cluster_z = uint(clamp((abs(view_pos.z) / params.z_far) * 32.0, 0.0, 31.0));
-
- vec3 total_light = params.light_color;
+ float density = 0.0;
+ vec3 emission = vec3(0.0);
+ vec3 albedo = vec3(0.0);
- float total_density = params.base_density;
float cell_depth_size = abs(view_pos.z - get_depth_at_pos(fog_cell_size.z, pos.z + 1));
- //compute directional lights
-
- for (uint i = 0; i < params.directional_light_count; i++) {
- vec3 shadow_attenuation = vec3(1.0);
-
- if (directional_lights.data[i].shadow_enabled) {
- float depth_z = -view_pos.z;
-
- vec4 pssm_coord;
- vec3 shadow_color = directional_lights.data[i].shadow_color1.rgb;
- vec3 light_dir = directional_lights.data[i].direction;
- vec4 v = vec4(view_pos, 1.0);
- float z_range;
-
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
- pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
- pssm_coord /= pssm_coord.w;
- z_range = directional_lights.data[i].shadow_z_range.x;
-
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
- pssm_coord /= pssm_coord.w;
- z_range = directional_lights.data[i].shadow_z_range.y;
-
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
- pssm_coord /= pssm_coord.w;
- z_range = directional_lights.data[i].shadow_z_range.z;
-
- } else {
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
- pssm_coord /= pssm_coord.w;
- z_range = directional_lights.data[i].shadow_z_range.w;
- }
-
- float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r;
- float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * directional_lights.data[i].shadow_volumetric_fog_fade);
-
- /*
- //float shadow = textureProj(sampler2DShadow(directional_shadow_atlas,shadow_sampler),pssm_coord);
- float shadow = 0.0;
- for(float xi=-1;xi<=1;xi++) {
- for(float yi=-1;yi<=1;yi++) {
- vec2 ofs = vec2(xi,yi) * 1.5 * params.directional_shadow_pixel_size;
- shadow += textureProj(sampler2DShadow(directional_shadow_atlas,shadow_sampler),pssm_coord + vec4(ofs,0.0,0.0));
- }
-
- }
-
- shadow /= 3.0 * 3.0;
-*/
- shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); //done with negative values for performance
-
- shadow_attenuation = mix(shadow_color, vec3(1.0), shadow);
- }
-
- total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy / M_PI;
+ vec4 world = scene_params.transform * vec4(view_pos, 1.0);
+ world.xyz /= world.w;
+
+ vec3 uvw = fog_unit_pos;
+
+ vec4 local_pos = params.transform * world;
+ local_pos.xyz /= local_pos.w;
+
+ float sdf = -1.0;
+ if (params.shape == 0) {
+ //Ellipsoid
+ // https://www.shadertoy.com/view/tdS3DG
+ float k0 = length(local_pos.xyz / params.extents);
+ float k1 = length(local_pos.xyz / (params.extents * params.extents));
+ sdf = k0 * (k0 - 1.0) / k1;
+ } else if (params.shape == 1) {
+ // Box
+ // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm
+ vec3 q = abs(local_pos.xyz) - params.extents;
+ sdf = length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
}
- //compute lights from cluster
-
- { //omni lights
-
- uint cluster_omni_offset = cluster_offset;
-
- uint item_min;
- uint item_max;
- uint item_from;
- uint item_to;
-
- cluster_get_item_range(cluster_omni_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
-
-#ifdef USE_SUBGROUPS
- item_from = subgroupBroadcastFirst(subgroupMin(item_from));
- item_to = subgroupBroadcastFirst(subgroupMax(item_to));
+ float cull_mask = 1.0; //used to cull cells that do not contribute
+ if (params.shape <= 1) {
+#ifndef SDF_USED
+ cull_mask = 1.0 - smoothstep(-0.1, 0.0, sdf);
#endif
+ uvw = clamp((local_pos.xyz + params.extents) / (2.0 * params.extents), 0.0, 1.0);
+ }
- for (uint i = item_from; i < item_to; i++) {
- uint mask = cluster_buffer.data[cluster_omni_offset + i];
- mask &= cluster_get_range_clip_mask(i, item_min, item_max);
-#ifdef USE_SUBGROUPS
- uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
+ if (cull_mask > 0.0) {
+ {
+#CODE : FOG
+ }
+
+#ifdef DENSITY_USED
+ density *= cull_mask;
+ if (abs(density) > 0.001) {
+ int final_density = int(density * DENSITY_SCALE);
+#ifdef MOLTENVK_USED
+ atomicAdd(density_only_map[lpos], uint(final_density));
#else
- uint merged_mask = mask;
+ imageAtomicAdd(density_only_map, pos, uint(final_density));
#endif
- while (merged_mask != 0) {
- uint bit = findMSB(merged_mask);
- merged_mask &= ~(1 << bit);
-#ifdef USE_SUBGROUPS
- if (((1 << bit) & mask) == 0) { //do not process if not originally here
- continue;
- }
+#ifdef EMISSION_USED
+ {
+ emission *= clamp(density, 0.0, 1.0);
+ emission = clamp(emission, vec3(0.0), vec3(4.0));
+ // Scale to fit into R11G11B10 with a range of 0-4
+ uvec3 emission_u = uvec3(emission.r * 511.0, emission.g * 511.0, emission.b * 255.0);
+ // R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint
+ uint final_emission = emission_u.r << 21 | emission_u.g << 10 | emission_u.b;
+#ifdef MOLTENVK_USED
+ uint prev_emission = atomicAdd(emissive_only_map[lpos], final_emission);
+#else
+ uint prev_emission = imageAtomicAdd(emissive_only_map, pos, final_emission);
#endif
- uint light_index = 32 * i + bit;
-
- //if (!bool(omni_omni_lights.data[light_index].mask & draw_call.layer_mask)) {
- // continue; //not masked
- //}
-
- vec3 light_pos = omni_lights.data[light_index].position;
- float d = distance(omni_lights.data[light_index].position, view_pos);
- float shadow_attenuation = 1.0;
-
- if (d * omni_lights.data[light_index].inv_radius < 1.0) {
- float attenuation = get_omni_attenuation(d, omni_lights.data[light_index].inv_radius, omni_lights.data[light_index].attenuation);
-
- vec3 light = omni_lights.data[light_index].color / M_PI;
-
- if (omni_lights.data[light_index].shadow_enabled) {
- //has shadow
- vec4 v = vec4(view_pos, 1.0);
-
- vec4 splane = (omni_lights.data[light_index].shadow_matrix * v);
- float shadow_len = length(splane.xyz); //need to remember shadow len from here
- splane.xyz = normalize(splane.xyz);
- vec4 clamp_rect = omni_lights.data[light_index].atlas_rect;
+ // Adding can lead to colors overflowing, so validate
+ uvec3 prev_emission_u = uvec3(prev_emission >> 21, (prev_emission << 11) >> 21, prev_emission % 1024);
+ uint add_emission = final_emission + prev_emission;
+ uvec3 add_emission_u = uvec3(add_emission >> 21, (add_emission << 11) >> 21, add_emission % 1024);
- if (splane.z >= 0.0) {
- splane.z += 1.0;
+ bvec3 overflowing = lessThan(add_emission_u, prev_emission_u + emission_u);
- 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 * omni_lights.data[light_index].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 depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r;
-
- shadow_attenuation = exp(min(0.0, (depth - splane.z)) / omni_lights.data[light_index].inv_radius * omni_lights.data[light_index].shadow_volumetric_fog_fade);
- }
- total_light += light * attenuation * shadow_attenuation;
+ if (any(overflowing)) {
+ uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing);
+ uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b;
+#ifdef MOLTENVK_USED
+ atomicOr(emissive_only_map[lpos], force_max);
+#else
+ imageAtomicOr(emissive_only_map, pos, force_max);
+#endif
}
}
- }
- }
-
- { //spot lights
-
- uint cluster_spot_offset = cluster_offset + params.cluster_type_size;
-
- uint item_min;
- uint item_max;
- uint item_from;
- uint item_to;
-
- cluster_get_item_range(cluster_spot_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
-
-#ifdef USE_SUBGROUPS
- item_from = subgroupBroadcastFirst(subgroupMin(item_from));
- item_to = subgroupBroadcastFirst(subgroupMax(item_to));
#endif
-
- for (uint i = item_from; i < item_to; i++) {
- uint mask = cluster_buffer.data[cluster_spot_offset + i];
- mask &= cluster_get_range_clip_mask(i, item_min, item_max);
-#ifdef USE_SUBGROUPS
- uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
+#ifdef ALBEDO_USED
+ {
+ vec3 scattering = albedo * clamp(density, 0.0, 1.0);
+ scattering = clamp(scattering, vec3(0.0), vec3(1.0));
+ uvec3 scattering_u = uvec3(scattering.r * 2047.0, scattering.g * 2047.0, scattering.b * 1023.0);
+ // R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint
+ uint final_scattering = scattering_u.r << 21 | scattering_u.g << 10 | scattering_u.b;
+#ifdef MOLTENVK_USED
+ uint prev_scattering = atomicAdd(light_only_map[lpos], final_scattering);
#else
- uint merged_mask = mask;
-#endif
-
- while (merged_mask != 0) {
- uint bit = findMSB(merged_mask);
- merged_mask &= ~(1 << bit);
-#ifdef USE_SUBGROUPS
- if (((1 << bit) & mask) == 0) { //do not process if not originally here
- continue;
- }
+ uint prev_scattering = imageAtomicAdd(light_only_map, pos, final_scattering);
#endif
- //if (!bool(omni_lights.data[light_index].mask & draw_call.layer_mask)) {
- // continue; //not masked
- //}
-
- uint light_index = 32 * i + bit;
-
- vec3 light_pos = spot_lights.data[light_index].position;
- vec3 light_rel_vec = spot_lights.data[light_index].position - view_pos;
- float d = length(light_rel_vec);
- float shadow_attenuation = 1.0;
-
- if (d * spot_lights.data[light_index].inv_radius < 1.0) {
- float attenuation = get_omni_attenuation(d, spot_lights.data[light_index].inv_radius, spot_lights.data[light_index].attenuation);
-
- vec3 spot_dir = spot_lights.data[light_index].direction;
- float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[light_index].cone_angle);
- float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[light_index].cone_angle));
- attenuation *= 1.0 - pow(spot_rim, spot_lights.data[light_index].cone_attenuation);
-
- vec3 light = spot_lights.data[light_index].color / M_PI;
-
- if (spot_lights.data[light_index].shadow_enabled) {
- //has shadow
- vec4 v = vec4(view_pos, 1.0);
-
- vec4 splane = (spot_lights.data[light_index].shadow_matrix * v);
- splane /= splane.w;
-
- float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r;
-
- shadow_attenuation = exp(min(0.0, (depth - splane.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade);
- }
-
- total_light += light * attenuation * shadow_attenuation;
- }
- }
- }
- }
-
- vec3 world_pos = mat3(params.cam_rotation) * view_pos;
-
- for (uint i = 0; i < params.max_gi_probes; i++) {
- vec3 position = (gi_probes.data[i].xform * vec4(world_pos, 1.0)).xyz;
-
- //this causes corrupted pixels, i have no idea why..
- if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, gi_probes.data[i].bounds))))) {
- position /= gi_probes.data[i].bounds;
-
- vec4 light = vec4(0.0);
- for (uint j = 0; j < gi_probes.data[i].mipmaps; j++) {
- vec4 slight = textureLod(sampler3D(gi_probe_textures[i], linear_sampler_with_mipmaps), position, float(j));
- float a = (1.0 - light.a);
- light += a * slight;
- }
-
- light.rgb *= gi_probes.data[i].dynamic_range * params.gi_inject;
-
- total_light += light.rgb;
- }
- }
-
- //sdfgi
-#ifdef ENABLE_SDFGI
+ // Adding can lead to colors overflowing, so validate
+ uvec3 prev_scattering_u = uvec3(prev_scattering >> 21, (prev_scattering << 11) >> 21, prev_scattering % 1024);
+ uint add_scattering = final_scattering + prev_scattering;
+ uvec3 add_scattering_u = uvec3(add_scattering >> 21, (add_scattering << 11) >> 21, add_scattering % 1024);
- {
- float blend = -1.0;
- vec3 ambient_total = vec3(0.0);
+ bvec3 overflowing = lessThan(add_scattering_u, prev_scattering_u + scattering_u);
- for (uint i = 0; i < sdfgi.max_cascades; i++) {
- vec3 cascade_pos = (world_pos - sdfgi.cascades[i].position) * sdfgi.cascades[i].to_probe;
-
- if (any(lessThan(cascade_pos, vec3(0.0))) || any(greaterThanEqual(cascade_pos, sdfgi.cascade_probe_size))) {
- continue; //skip cascade
- }
-
- vec3 base_pos = floor(cascade_pos);
- ivec3 probe_base_pos = ivec3(base_pos);
-
- vec4 ambient_accum = vec4(0.0);
-
- ivec3 tex_pos = ivec3(probe_base_pos.xy, int(i));
- tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size;
-
- for (uint j = 0; j < 8; j++) {
- ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1);
- ivec3 probe_posi = probe_base_pos;
- probe_posi += offset;
-
- // Compute weight
-
- vec3 probe_pos = vec3(probe_posi);
- vec3 probe_to_pos = cascade_pos - probe_pos;
-
- vec3 trilinear = vec3(1.0) - abs(probe_to_pos);
- float weight = trilinear.x * trilinear.y * trilinear.z;
-
- // Compute lightprobe occlusion
-
- if (sdfgi.use_occlusion) {
- ivec3 occ_indexv = abs((sdfgi.cascades[i].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4);
- vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3)));
-
- vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw;
- occ_pos.z += float(i);
- if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures
- occ_pos.x += 1.0;
- }
-
- occ_pos *= sdfgi.occlusion_renormalize;
- float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_texture, linear_sampler), occ_pos, 0.0), occ_mask);
-
- weight *= max(occlusion, 0.01);
+ if (any(overflowing)) {
+ uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing);
+ uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b;
+#ifdef MOLTENVK_USED
+ atomicOr(light_only_map[lpos], force_max);
+#else
+ imageAtomicOr(light_only_map, pos, force_max);
+#endif
}
-
- // Compute ambient texture position
-
- ivec3 uvw = tex_pos;
- uvw.xy += offset.xy;
- uvw.x += offset.z * sdfgi.probe_axis_size;
-
- vec3 ambient = texelFetch(sampler2DArray(sdfgi_ambient_texture, linear_sampler), uvw, 0).rgb;
-
- ambient_accum.rgb += ambient * weight;
- ambient_accum.a += weight;
- }
-
- if (ambient_accum.a > 0) {
- ambient_accum.rgb /= ambient_accum.a;
}
- ambient_total = ambient_accum.rgb;
- break;
+#endif // ALBEDO_USED
}
-
- total_light += ambient_total * params.gi_inject;
+#endif // DENSITY_USED
}
-
-#endif
-
- vec4 final_density = vec4(total_light, total_density);
-
- final_density = mix(final_density, reprojected_density, reproject_amount);
-
- imageStore(density_map, pos, final_density);
-#endif
-
-#ifdef MODE_FOG
-
- ivec3 pos = ivec3(gl_GlobalInvocationID.xy, 0);
-
- if (any(greaterThanEqual(pos, params.fog_volume_size))) {
- return; //do not compute
- }
-
- vec4 fog_accum = vec4(0.0);
- float prev_z = 0.0;
-
- float t = 1.0;
-
- for (int i = 0; i < params.fog_volume_size.z; i++) {
- //compute fog position
- ivec3 fog_pos = pos + ivec3(0, 0, i);
- //get fog value
- vec4 fog = imageLoad(density_map, fog_pos);
-
- //get depth at cell pos
- float z = get_depth_at_pos(fog_cell_size.z, i);
- //get distance from previous pos
- float d = abs(prev_z - z);
- //compute exinction based on beer's
- float extinction = t * exp(-d * fog.a);
- //compute alpha based on different of extinctions
- float alpha = t - extinction;
- //update extinction
- t = extinction;
-
- fog_accum += vec4(fog.rgb * alpha, alpha);
- prev_z = z;
-
- vec4 fog_value;
-
- if (fog_accum.a > 0.0) {
- fog_value = vec4(fog_accum.rgb / fog_accum.a, 1.0 - t);
- } else {
- fog_value = vec4(0.0);
- }
-
- imageStore(fog_map, fog_pos, fog_value);
- }
-
-#endif
-
-#ifdef MODE_FILTER
-
- ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
-
- const float gauss[7] = float[](0.071303, 0.131514, 0.189879, 0.214607, 0.189879, 0.131514, 0.071303);
-
- const ivec3 filter_dir[3] = ivec3[](ivec3(1, 0, 0), ivec3(0, 1, 0), ivec3(0, 0, 1));
- ivec3 offset = filter_dir[params.filter_axis];
-
- vec4 accum = vec4(0.0);
- for (int i = -3; i <= 3; i++) {
- accum += imageLoad(source_map, clamp(pos + offset * i, ivec3(0), params.fog_volume_size - ivec3(1))) * gauss[i + 3];
- }
-
- imageStore(dest_map, pos, accum);
-
-#endif
}
diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl
new file mode 100644
index 0000000000..747f88960c
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl
@@ -0,0 +1,776 @@
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+/* Do not use subgroups here, seems there is not much advantage and causes glitches
+#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic)
+#extension GL_KHR_shader_subgroup_ballot: enable
+#extension GL_KHR_shader_subgroup_arithmetic: enable
+
+#define USE_SUBGROUPS
+#endif
+*/
+
+#ifdef MODE_DENSITY
+layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
+#else
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+#endif
+
+#include "cluster_data_inc.glsl"
+#include "light_data_inc.glsl"
+
+#define M_PI 3.14159265359
+
+#define DENSITY_SCALE 1024.0
+
+layout(set = 0, binding = 1) uniform texture2D shadow_atlas;
+layout(set = 0, binding = 2) uniform texture2D directional_shadow_atlas;
+
+layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
+ LightData data[];
+}
+omni_lights;
+
+layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
+ LightData data[];
+}
+spot_lights;
+
+layout(set = 0, binding = 5, std140) uniform DirectionalLights {
+ DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+}
+directional_lights;
+
+layout(set = 0, binding = 6, std430) buffer restrict readonly ClusterBuffer {
+ uint data[];
+}
+cluster_buffer;
+
+layout(set = 0, binding = 7) uniform sampler linear_sampler;
+
+#ifdef MODE_DENSITY
+layout(rgba16f, set = 0, binding = 8) uniform restrict writeonly image3D density_map;
+layout(rgba16f, set = 0, binding = 9) uniform restrict readonly image3D fog_map; //unused
+#endif
+
+#ifdef MODE_FOG
+layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D density_map;
+layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D fog_map;
+#endif
+
+#ifdef MODE_COPY
+layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map;
+layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map;
+#endif
+
+#ifdef MODE_FILTER
+layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map;
+layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map;
+#endif
+
+layout(set = 0, binding = 10) uniform sampler shadow_sampler;
+
+#define MAX_VOXEL_GI_INSTANCES 8
+
+struct VoxelGIData {
+ mat4 xform;
+ vec3 bounds;
+ float dynamic_range;
+
+ float bias;
+ float normal_bias;
+ bool blend_ambient;
+ uint texture_slot;
+
+ float anisotropy_strength;
+ float ambient_occlusion;
+ float ambient_occlusion_size;
+ uint mipmaps;
+};
+
+layout(set = 0, binding = 11, std140) uniform VoxelGIs {
+ VoxelGIData data[MAX_VOXEL_GI_INSTANCES];
+}
+voxel_gi_instances;
+
+layout(set = 0, binding = 12) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
+
+layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps;
+
+#ifdef ENABLE_SDFGI
+
+// SDFGI Integration on set 1
+#define SDFGI_MAX_CASCADES 8
+
+struct SDFVoxelGICascadeData {
+ vec3 position;
+ float to_probe;
+ ivec3 probe_world_offset;
+ float to_cell; // 1/bounds * grid_size
+};
+
+layout(set = 1, binding = 0, std140) uniform SDFGI {
+ vec3 grid_size;
+ uint max_cascades;
+
+ bool use_occlusion;
+ int probe_axis_size;
+ float probe_to_uvw;
+ float normal_bias;
+
+ vec3 lightprobe_tex_pixel_size;
+ float energy;
+
+ vec3 lightprobe_uv_offset;
+ float y_mult;
+
+ vec3 occlusion_clamp;
+ uint pad3;
+
+ vec3 occlusion_renormalize;
+ uint pad4;
+
+ vec3 cascade_probe_size;
+ uint pad5;
+
+ SDFVoxelGICascadeData cascades[SDFGI_MAX_CASCADES];
+}
+sdfgi;
+
+layout(set = 1, binding = 1) uniform texture2DArray sdfgi_ambient_texture;
+
+layout(set = 1, binding = 2) uniform texture3D sdfgi_occlusion_texture;
+
+#endif //SDFGI
+
+layout(set = 0, binding = 14, std140) uniform Params {
+ vec2 fog_frustum_size_begin;
+ vec2 fog_frustum_size_end;
+
+ float fog_frustum_end;
+ float ambient_inject;
+ float z_far;
+ int filter_axis;
+
+ vec3 ambient_color;
+ float sky_contribution;
+
+ ivec3 fog_volume_size;
+ uint directional_light_count;
+
+ vec3 base_emission;
+ float base_density;
+
+ vec3 base_scattering;
+ float phase_g;
+
+ float detail_spread;
+ float gi_inject;
+ uint max_voxel_gi_instances;
+ uint cluster_type_size;
+
+ vec2 screen_size;
+ uint cluster_shift;
+ uint cluster_width;
+
+ uint max_cluster_element_count_div_32;
+ bool use_temporal_reprojection;
+ uint temporal_frame;
+ float temporal_blend;
+
+ mat3x4 cam_rotation;
+ mat4 to_prev_view;
+
+ mat3 radiance_inverse_xform;
+}
+params;
+#ifndef MODE_COPY
+layout(set = 0, binding = 15) uniform texture3D prev_density_texture;
+
+#ifdef MOLTENVK_USED
+layout(set = 0, binding = 16) buffer density_only_map_buffer {
+ uint density_only_map[];
+};
+layout(set = 0, binding = 17) buffer light_only_map_buffer {
+ uint light_only_map[];
+};
+layout(set = 0, binding = 18) buffer emissive_only_map_buffer {
+ uint emissive_only_map[];
+};
+#else
+layout(r32ui, set = 0, binding = 16) uniform uimage3D density_only_map;
+layout(r32ui, set = 0, binding = 17) uniform uimage3D light_only_map;
+layout(r32ui, set = 0, binding = 18) uniform uimage3D emissive_only_map;
+#endif
+
+#ifdef USE_RADIANCE_CUBEMAP_ARRAY
+layout(set = 0, binding = 19) uniform textureCubeArray sky_texture;
+#else
+layout(set = 0, binding = 19) uniform textureCube sky_texture;
+#endif
+#endif // MODE_COPY
+
+float get_depth_at_pos(float cell_depth_size, int z) {
+ float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels
+ d = pow(d, params.detail_spread);
+ return params.fog_frustum_end * d;
+}
+
+vec3 hash3f(uvec3 x) {
+ x = ((x >> 16) ^ x) * 0x45d9f3b;
+ x = ((x >> 16) ^ x) * 0x45d9f3b;
+ x = (x >> 16) ^ x;
+ return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF));
+}
+
+float get_omni_attenuation(float dist, float inv_range, float decay) {
+ float nd = dist * inv_range;
+ nd *= nd;
+ nd *= nd; // nd^4
+ nd = max(1.0 - nd, 0.0);
+ nd *= nd; // nd^2
+ return nd * pow(max(dist, 0.0001), -decay);
+}
+
+void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) {
+ uint item_min_max = cluster_buffer.data[p_offset];
+ item_min = item_min_max & 0xFFFF;
+ item_max = item_min_max >> 16;
+ ;
+
+ item_from = item_min >> 5;
+ item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements
+}
+
+uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) {
+ int local_min = clamp(int(z_min) - int(i) * 32, 0, 31);
+ int mask_width = min(int(z_max) - int(z_min), 32 - local_min);
+ return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width);
+}
+
+float henyey_greenstein(float cos_theta, float g) {
+ const float k = 0.0795774715459; // 1 / (4 * PI)
+ return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5));
+}
+
+#define TEMPORAL_FRAMES 16
+
+const vec3 halton_map[TEMPORAL_FRAMES] = vec3[](
+ vec3(0.5, 0.33333333, 0.2),
+ vec3(0.25, 0.66666667, 0.4),
+ vec3(0.75, 0.11111111, 0.6),
+ vec3(0.125, 0.44444444, 0.8),
+ vec3(0.625, 0.77777778, 0.04),
+ vec3(0.375, 0.22222222, 0.24),
+ vec3(0.875, 0.55555556, 0.44),
+ vec3(0.0625, 0.88888889, 0.64),
+ vec3(0.5625, 0.03703704, 0.84),
+ vec3(0.3125, 0.37037037, 0.08),
+ vec3(0.8125, 0.7037037, 0.28),
+ vec3(0.1875, 0.14814815, 0.48),
+ vec3(0.6875, 0.48148148, 0.68),
+ vec3(0.4375, 0.81481481, 0.88),
+ vec3(0.9375, 0.25925926, 0.12),
+ vec3(0.03125, 0.59259259, 0.32));
+
+void main() {
+ vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size);
+
+#ifdef MODE_DENSITY
+
+ ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
+ if (any(greaterThanEqual(pos, params.fog_volume_size))) {
+ return; //do not compute
+ }
+#ifdef MOLTENVK_USED
+ uint lpos = pos.z * params.fog_volume_size.x * params.fog_volume_size.y + pos.y * params.fog_volume_size.x + pos.x;
+#endif
+
+ vec3 posf = vec3(pos);
+
+ //posf += mix(vec3(0.0),vec3(1.0),0.3) * hash3f(uvec3(pos)) * 2.0 - 1.0;
+
+ vec3 fog_unit_pos = posf * fog_cell_size + fog_cell_size * 0.5; //center of voxels
+
+ uvec2 screen_pos = uvec2(fog_unit_pos.xy * params.screen_size);
+ uvec2 cluster_pos = screen_pos >> params.cluster_shift;
+ uint cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32);
+ //positions in screen are too spread apart, no hopes for optimizing with subgroups
+
+ fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread);
+
+ vec3 view_pos;
+ view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z));
+ view_pos.z = -params.fog_frustum_end * fog_unit_pos.z;
+ view_pos.y = -view_pos.y;
+
+ vec4 reprojected_density = vec4(0.0);
+ float reproject_amount = 0.0;
+
+ if (params.use_temporal_reprojection) {
+ vec3 prev_view = (params.to_prev_view * vec4(view_pos, 1.0)).xyz;
+ //undo transform into prev view
+ prev_view.y = -prev_view.y;
+ //z back to unit size
+ prev_view.z /= -params.fog_frustum_end;
+ //xy back to unit size
+ prev_view.xy /= mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(prev_view.z));
+ prev_view.xy = prev_view.xy * 0.5 + 0.5;
+ //z back to unspread value
+ prev_view.z = pow(prev_view.z, 1.0 / params.detail_spread);
+
+ if (all(greaterThan(prev_view, vec3(0.0))) && all(lessThan(prev_view, vec3(1.0)))) {
+ //reprojectinon fits
+
+ reprojected_density = textureLod(sampler3D(prev_density_texture, linear_sampler), prev_view, 0.0);
+ reproject_amount = params.temporal_blend;
+
+ // Since we can reproject, now we must jitter the current view pos.
+ // This is done here because cells that can't reproject should not jitter.
+
+ fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[params.temporal_frame]; //center of voxels, offset by halton table
+
+ screen_pos = uvec2(fog_unit_pos.xy * params.screen_size);
+ cluster_pos = screen_pos >> params.cluster_shift;
+ cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32);
+ //positions in screen are too spread apart, no hopes for optimizing with subgroups
+
+ fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread);
+
+ view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z));
+ view_pos.z = -params.fog_frustum_end * fog_unit_pos.z;
+ view_pos.y = -view_pos.y;
+ }
+ }
+
+ uint cluster_z = uint(clamp((abs(view_pos.z) / params.z_far) * 32.0, 0.0, 31.0));
+
+ vec3 total_light = vec3(0.0);
+
+ float total_density = params.base_density;
+#ifdef MOLTENVK_USED
+ uint local_density = density_only_map[lpos];
+#else
+ uint local_density = imageLoad(density_only_map, pos).x;
+#endif
+
+ total_density += float(int(local_density)) / DENSITY_SCALE;
+ total_density = max(0.0, total_density);
+
+#ifdef MOLTENVK_USED
+ uint scattering_u = light_only_map[lpos];
+#else
+ uint scattering_u = imageLoad(light_only_map, pos).x;
+#endif
+ vec3 scattering = vec3(scattering_u >> 21, (scattering_u << 11) >> 21, scattering_u % 1024) / vec3(2047.0, 2047.0, 1023.0);
+ scattering += params.base_scattering * params.base_density;
+
+#ifdef MOLTENVK_USED
+ uint emission_u = emissive_only_map[lpos];
+#else
+ uint emission_u = imageLoad(emissive_only_map, pos).x;
+#endif
+ vec3 emission = vec3(emission_u >> 21, (emission_u << 11) >> 21, emission_u % 1024) / vec3(511.0, 511.0, 255.0);
+ emission += params.base_emission * params.base_density;
+
+ float cell_depth_size = abs(view_pos.z - get_depth_at_pos(fog_cell_size.z, pos.z + 1));
+ //compute directional lights
+
+ if (total_density > 0.001) {
+ for (uint i = 0; i < params.directional_light_count; i++) {
+ vec3 shadow_attenuation = vec3(1.0);
+
+ if (directional_lights.data[i].shadow_enabled) {
+ float depth_z = -view_pos.z;
+
+ vec4 pssm_coord;
+ vec3 shadow_color = directional_lights.data[i].shadow_color1.rgb;
+ vec3 light_dir = directional_lights.data[i].direction;
+ vec4 v = vec4(view_pos, 1.0);
+ float z_range;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.x;
+
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.y;
+
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.z;
+
+ } else {
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.w;
+ }
+
+ float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r;
+ float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * directional_lights.data[i].shadow_volumetric_fog_fade);
+
+ shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); //done with negative values for performance
+
+ shadow_attenuation = mix(shadow_color, vec3(1.0), shadow);
+ }
+
+ total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy * henyey_greenstein(dot(normalize(view_pos), normalize(directional_lights.data[i].direction)), params.phase_g);
+ }
+
+ // Compute light from sky
+ if (params.ambient_inject > 0.0) {
+ vec3 isotropic = vec3(0.0);
+ vec3 anisotropic = vec3(0.0);
+ if (params.sky_contribution > 0.0) {
+ float mip_bias = 2.0 + total_density * (MAX_SKY_LOD - 2.0); // Not physically based, but looks nice
+ vec3 scatter_direction = (params.radiance_inverse_xform * normalize(view_pos)) * sign(params.phase_g);
+#ifdef USE_RADIANCE_CUBEMAP_ARRAY
+ isotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(0.0, 1.0, 0.0, mip_bias)).rgb;
+ anisotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(scatter_direction, mip_bias)).rgb;
+#else
+ isotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(0.0, 1.0, 0.0), mip_bias).rgb;
+ anisotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(scatter_direction), mip_bias).rgb;
+#endif //USE_RADIANCE_CUBEMAP_ARRAY
+ }
+
+ total_light += mix(params.ambient_color, mix(isotropic, anisotropic, abs(params.phase_g)), params.sky_contribution) * params.ambient_inject;
+ }
+
+ //compute lights from cluster
+
+ { //omni lights
+
+ uint cluster_omni_offset = cluster_offset;
+
+ uint item_min;
+ uint item_max;
+ uint item_from;
+ uint item_to;
+
+ cluster_get_item_range(cluster_omni_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+
+#ifdef USE_SUBGROUPS
+ item_from = subgroupBroadcastFirst(subgroupMin(item_from));
+ item_to = subgroupBroadcastFirst(subgroupMax(item_to));
+#endif
+
+ for (uint i = item_from; i < item_to; i++) {
+ uint mask = cluster_buffer.data[cluster_omni_offset + i];
+ mask &= cluster_get_range_clip_mask(i, item_min, item_max);
+#ifdef USE_SUBGROUPS
+ uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
+#else
+ uint merged_mask = mask;
+#endif
+
+ while (merged_mask != 0) {
+ uint bit = findMSB(merged_mask);
+ merged_mask &= ~(1 << bit);
+#ifdef USE_SUBGROUPS
+ if (((1 << bit) & mask) == 0) { //do not process if not originally here
+ continue;
+ }
+#endif
+ uint light_index = 32 * i + bit;
+
+ //if (!bool(omni_omni_lights.data[light_index].mask & draw_call.layer_mask)) {
+ // continue; //not masked
+ //}
+
+ vec3 light_pos = omni_lights.data[light_index].position;
+ float d = distance(omni_lights.data[light_index].position, view_pos);
+ float shadow_attenuation = 1.0;
+
+ if (d * omni_lights.data[light_index].inv_radius < 1.0) {
+ float attenuation = get_omni_attenuation(d, omni_lights.data[light_index].inv_radius, omni_lights.data[light_index].attenuation);
+
+ vec3 light = omni_lights.data[light_index].color;
+
+ if (omni_lights.data[light_index].shadow_enabled) {
+ //has shadow
+ vec4 uv_rect = omni_lights.data[light_index].atlas_rect;
+ vec2 flip_offset = omni_lights.data[light_index].direction.xy;
+
+ vec3 local_vert = (omni_lights.data[light_index].shadow_matrix * vec4(view_pos, 1.0)).xyz;
+
+ float shadow_len = length(local_vert); //need to remember shadow len from here
+ vec3 shadow_sample = normalize(local_vert);
+
+ if (shadow_sample.z >= 0.0) {
+ uv_rect.xy += flip_offset;
+ }
+
+ shadow_sample.z = 1.0 + abs(shadow_sample.z);
+ vec3 pos = vec3(shadow_sample.xy / shadow_sample.z, shadow_len - omni_lights.data[light_index].shadow_bias);
+ pos.z *= omni_lights.data[light_index].inv_radius;
+
+ pos.xy = pos.xy * 0.5 + 0.5;
+ pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
+
+ float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r;
+
+ shadow_attenuation = exp(min(0.0, (depth - pos.z)) / omni_lights.data[light_index].inv_radius * omni_lights.data[light_index].shadow_volumetric_fog_fade);
+ }
+ total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_pos - view_pos), normalize(view_pos)), params.phase_g);
+ }
+ }
+ }
+ }
+
+ { //spot lights
+
+ uint cluster_spot_offset = cluster_offset + params.cluster_type_size;
+
+ uint item_min;
+ uint item_max;
+ uint item_from;
+ uint item_to;
+
+ cluster_get_item_range(cluster_spot_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+
+#ifdef USE_SUBGROUPS
+ item_from = subgroupBroadcastFirst(subgroupMin(item_from));
+ item_to = subgroupBroadcastFirst(subgroupMax(item_to));
+#endif
+
+ for (uint i = item_from; i < item_to; i++) {
+ uint mask = cluster_buffer.data[cluster_spot_offset + i];
+ mask &= cluster_get_range_clip_mask(i, item_min, item_max);
+#ifdef USE_SUBGROUPS
+ uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
+#else
+ uint merged_mask = mask;
+#endif
+
+ while (merged_mask != 0) {
+ uint bit = findMSB(merged_mask);
+ merged_mask &= ~(1 << bit);
+#ifdef USE_SUBGROUPS
+ if (((1 << bit) & mask) == 0) { //do not process if not originally here
+ continue;
+ }
+#endif
+
+ //if (!bool(omni_lights.data[light_index].mask & draw_call.layer_mask)) {
+ // continue; //not masked
+ //}
+
+ uint light_index = 32 * i + bit;
+
+ vec3 light_pos = spot_lights.data[light_index].position;
+ vec3 light_rel_vec = spot_lights.data[light_index].position - view_pos;
+ float d = length(light_rel_vec);
+ float shadow_attenuation = 1.0;
+
+ if (d * spot_lights.data[light_index].inv_radius < 1.0) {
+ float attenuation = get_omni_attenuation(d, spot_lights.data[light_index].inv_radius, spot_lights.data[light_index].attenuation);
+
+ vec3 spot_dir = spot_lights.data[light_index].direction;
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[light_index].cone_angle);
+ float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[light_index].cone_angle));
+ attenuation *= 1.0 - pow(spot_rim, spot_lights.data[light_index].cone_attenuation);
+
+ vec3 light = spot_lights.data[light_index].color;
+
+ if (spot_lights.data[light_index].shadow_enabled) {
+ //has shadow
+ vec4 v = vec4(view_pos, 1.0);
+
+ vec4 splane = (spot_lights.data[light_index].shadow_matrix * v);
+ splane /= splane.w;
+
+ float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r;
+
+ shadow_attenuation = exp(min(0.0, (depth - splane.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade);
+ }
+
+ total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g);
+ }
+ }
+ }
+ }
+
+ vec3 world_pos = mat3(params.cam_rotation) * view_pos;
+
+ for (uint i = 0; i < params.max_voxel_gi_instances; i++) {
+ vec3 position = (voxel_gi_instances.data[i].xform * vec4(world_pos, 1.0)).xyz;
+
+ //this causes corrupted pixels, i have no idea why..
+ if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, voxel_gi_instances.data[i].bounds))))) {
+ position /= voxel_gi_instances.data[i].bounds;
+
+ vec4 light = vec4(0.0);
+ for (uint j = 0; j < voxel_gi_instances.data[i].mipmaps; j++) {
+ vec4 slight = textureLod(sampler3D(voxel_gi_textures[i], linear_sampler_with_mipmaps), position, float(j));
+ float a = (1.0 - light.a);
+ light += a * slight;
+ }
+
+ light.rgb *= voxel_gi_instances.data[i].dynamic_range * params.gi_inject;
+
+ total_light += light.rgb;
+ }
+ }
+
+ //sdfgi
+#ifdef ENABLE_SDFGI
+
+ {
+ float blend = -1.0;
+ vec3 ambient_total = vec3(0.0);
+
+ for (uint i = 0; i < sdfgi.max_cascades; i++) {
+ vec3 cascade_pos = (world_pos - sdfgi.cascades[i].position) * sdfgi.cascades[i].to_probe;
+
+ if (any(lessThan(cascade_pos, vec3(0.0))) || any(greaterThanEqual(cascade_pos, sdfgi.cascade_probe_size))) {
+ continue; //skip cascade
+ }
+
+ vec3 base_pos = floor(cascade_pos);
+ ivec3 probe_base_pos = ivec3(base_pos);
+
+ vec4 ambient_accum = vec4(0.0);
+
+ ivec3 tex_pos = ivec3(probe_base_pos.xy, int(i));
+ tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size;
+
+ for (uint j = 0; j < 8; j++) {
+ ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1);
+ ivec3 probe_posi = probe_base_pos;
+ probe_posi += offset;
+
+ // Compute weight
+
+ vec3 probe_pos = vec3(probe_posi);
+ vec3 probe_to_pos = cascade_pos - probe_pos;
+
+ vec3 trilinear = vec3(1.0) - abs(probe_to_pos);
+ float weight = trilinear.x * trilinear.y * trilinear.z;
+
+ // Compute lightprobe occlusion
+
+ if (sdfgi.use_occlusion) {
+ ivec3 occ_indexv = abs((sdfgi.cascades[i].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4);
+ vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3)));
+
+ vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw;
+ occ_pos.z += float(i);
+ if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures
+ occ_pos.x += 1.0;
+ }
+
+ occ_pos *= sdfgi.occlusion_renormalize;
+ float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_texture, linear_sampler), occ_pos, 0.0), occ_mask);
+
+ weight *= max(occlusion, 0.01);
+ }
+
+ // Compute ambient texture position
+
+ ivec3 uvw = tex_pos;
+ uvw.xy += offset.xy;
+ uvw.x += offset.z * sdfgi.probe_axis_size;
+
+ vec3 ambient = texelFetch(sampler2DArray(sdfgi_ambient_texture, linear_sampler), uvw, 0).rgb;
+
+ ambient_accum.rgb += ambient * weight;
+ ambient_accum.a += weight;
+ }
+
+ if (ambient_accum.a > 0) {
+ ambient_accum.rgb /= ambient_accum.a;
+ }
+ ambient_total = ambient_accum.rgb;
+ break;
+ }
+
+ total_light += ambient_total * params.gi_inject;
+ }
+
+#endif
+ }
+
+ vec4 final_density = vec4(total_light * scattering + emission, total_density);
+
+ final_density = mix(final_density, reprojected_density, reproject_amount);
+
+ imageStore(density_map, pos, final_density);
+#ifdef MOLTENVK_USED
+ density_only_map[lpos] = 0;
+ light_only_map[lpos] = 0;
+ emissive_only_map[lpos] = 0;
+#else
+ imageStore(density_only_map, pos, uvec4(0));
+ imageStore(light_only_map, pos, uvec4(0));
+ imageStore(emissive_only_map, pos, uvec4(0));
+#endif
+#endif
+
+#ifdef MODE_FOG
+
+ ivec3 pos = ivec3(gl_GlobalInvocationID.xy, 0);
+
+ if (any(greaterThanEqual(pos, params.fog_volume_size))) {
+ return; //do not compute
+ }
+
+ vec4 fog_accum = vec4(0.0, 0.0, 0.0, 1.0);
+ float prev_z = 0.0;
+
+ for (int i = 0; i < params.fog_volume_size.z; i++) {
+ //compute fog position
+ ivec3 fog_pos = pos + ivec3(0, 0, i);
+ //get fog value
+ vec4 fog = imageLoad(density_map, fog_pos);
+
+ //get depth at cell pos
+ float z = get_depth_at_pos(fog_cell_size.z, i);
+ //get distance from previous pos
+ float d = abs(prev_z - z);
+ //compute transmittance using beer's law
+ float transmittance = exp(-d * fog.a);
+
+ fog_accum.rgb += ((fog.rgb - fog.rgb * transmittance) / max(fog.a, 0.00001)) * fog_accum.a;
+ fog_accum.a *= transmittance;
+
+ prev_z = z;
+
+ imageStore(fog_map, fog_pos, vec4(fog_accum.rgb, 1.0 - fog_accum.a));
+ }
+
+#endif
+
+#ifdef MODE_FILTER
+
+ ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
+
+ const float gauss[7] = float[](0.071303, 0.131514, 0.189879, 0.214607, 0.189879, 0.131514, 0.071303);
+
+ const ivec3 filter_dir[3] = ivec3[](ivec3(1, 0, 0), ivec3(0, 1, 0), ivec3(0, 0, 1));
+ ivec3 offset = filter_dir[params.filter_axis];
+
+ vec4 accum = vec4(0.0);
+ for (int i = -3; i <= 3; i++) {
+ accum += imageLoad(source_map, clamp(pos + offset * i, ivec3(0), params.fog_volume_size - ivec3(1))) * gauss[i + 3];
+ }
+
+ imageStore(dest_map, pos, accum);
+
+#endif
+#ifdef MODE_COPY
+ ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
+ if (any(greaterThanEqual(pos, params.fog_volume_size))) {
+ return; //do not compute
+ }
+
+ imageStore(dest_map, pos, imageLoad(source_map, pos));
+
+#endif
+}
diff --git a/servers/rendering/renderer_rd/shaders/giprobe.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi.glsl
index 49a493cdc7..779f04ed35 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe.glsl
+++ b/servers/rendering/renderer_rd/shaders/voxel_gi.glsl
@@ -71,11 +71,6 @@ lights;
layout(set = 0, binding = 5) uniform texture3D color_texture;
-#ifdef MODE_ANISOTROPIC
-layout(set = 0, binding = 7) uniform texture3D aniso_pos_texture;
-layout(set = 0, binding = 8) uniform texture3D aniso_neg_texture;
-#endif // MODE ANISOTROPIC
-
#endif // MODE_SECOND_BOUNCE
#ifndef MODE_DYNAMIC
@@ -110,13 +105,6 @@ layout(set = 0, binding = 10) uniform sampler texture_sampler;
layout(rgba8, set = 0, binding = 5) uniform restrict writeonly image3D color_tex;
-#ifdef MODE_ANISOTROPIC
-
-layout(r16ui, set = 0, binding = 6) uniform restrict writeonly uimage3D aniso_pos_tex;
-layout(r16ui, set = 0, binding = 7) uniform restrict writeonly uimage3D aniso_neg_tex;
-
-#endif
-
#endif
#ifdef MODE_DYNAMIC
@@ -170,13 +158,6 @@ layout(r32f, set = 0, binding = 8) uniform restrict writeonly image2D depth;
layout(rgba8, set = 0, binding = 11) uniform restrict image3D color_texture;
-#ifdef MODE_ANISOTROPIC
-
-layout(r16ui, set = 0, binding = 12) uniform restrict writeonly uimage3D aniso_pos_texture;
-layout(r16ui, set = 0, binding = 13) uniform restrict writeonly uimage3D aniso_neg_texture;
-
-#endif // MODE ANISOTROPIC
-
#endif //MODE_DYNAMIC_SHRINK_PLOT
#endif // MODE_DYNAMIC_SHRINK
@@ -374,12 +355,7 @@ void main() {
vec3 emission = vec3(uvec3(cell_data.data[cell_index].emission & 0x1ff, (cell_data.data[cell_index].emission >> 9) & 0x1ff, (cell_data.data[cell_index].emission >> 18) & 0x1ff)) * pow(2.0, float(cell_data.data[cell_index].emission >> 27) - 15.0 - 9.0);
vec3 normal = unpackSnorm4x8(cell_data.data[cell_index].normal).xyz;
-#ifdef MODE_ANISOTROPIC
- vec3 accum[6] = vec3[](vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
- const vec3 accum_dirs[6] = vec3[](vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0));
-#else
vec3 accum = vec3(0.0);
-#endif
for (uint i = 0; i < params.light_count; i++) {
vec3 light;
@@ -390,38 +366,16 @@ void main() {
light *= albedo.rgb;
-#ifdef MODE_ANISOTROPIC
- for (uint j = 0; j < 6; j++) {
- accum[j] += max(0.0, dot(accum_dirs[j], -light_dir)) * light;
- }
-#else
if (length(normal) > 0.2) {
accum += max(0.0, dot(normal, -light_dir)) * light;
} else {
//all directions
accum += light;
}
-#endif
}
-#ifdef MODE_ANISOTROPIC
-
- for (uint i = 0; i < 6; i++) {
- vec3 light = accum[i];
- if (length(normal) > 0.2) {
- light += max(0.0, dot(accum_dirs[i], -normal)) * emission;
- } else {
- light += emission;
- }
-
- outputs.data[cell_index * 6 + i] = vec4(light, 0.0);
- }
-
-#else
outputs.data[cell_index] = vec4(accum + emission, 0.0);
-#endif
-
#endif //MODE_COMPUTE_LIGHT
/////////////////SECOND BOUNCE///////////////////////////////
@@ -431,32 +385,8 @@ void main() {
ivec3 ipos = ivec3(posu);
vec4 normal = unpackSnorm4x8(cell_data.data[cell_index].normal);
-#ifdef MODE_ANISOTROPIC
- vec3 accum[6];
- const vec3 accum_dirs[6] = vec3[](vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0));
-
- /*vec3 src_color = texelFetch(sampler3D(color_texture,texture_sampler),ipos,0).rgb * params.dynamic_range;
- vec3 src_aniso_pos = texelFetch(sampler3D(aniso_pos_texture,texture_sampler),ipos,0).rgb;
- vec3 src_anisp_neg = texelFetch(sampler3D(anisp_neg_texture,texture_sampler),ipos,0).rgb;
- accum[0]=src_col * src_aniso_pos.x;
- accum[1]=src_col * src_aniso_neg.x;
- accum[2]=src_col * src_aniso_pos.y;
- accum[3]=src_col * src_aniso_neg.y;
- accum[4]=src_col * src_aniso_pos.z;
- accum[5]=src_col * src_aniso_neg.z;*/
-
- accum[0] = outputs.data[cell_index * 6 + 0].rgb;
- accum[1] = outputs.data[cell_index * 6 + 1].rgb;
- accum[2] = outputs.data[cell_index * 6 + 2].rgb;
- accum[3] = outputs.data[cell_index * 6 + 3].rgb;
- accum[4] = outputs.data[cell_index * 6 + 4].rgb;
- accum[5] = outputs.data[cell_index * 6 + 5].rgb;
-
-#else
vec3 accum = outputs.data[cell_index].rgb;
-#endif
-
if (length(normal.xyz) > 0.2) {
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.xyz));
@@ -484,9 +414,6 @@ void main() {
float max_distance = length(vec3(params.limits));
vec3 cell_size = 1.0 / vec3(params.limits);
-#ifdef MODE_ANISOTROPIC
- vec3 aniso_normal = mix(direction, normal.xyz, params.aniso_strength);
-#endif
while (dist < max_distance && color.a < 0.95) {
float diameter = max(1.0, 2.0 * tan_half_angle * dist);
vec3 uvw_pos = (pos + dist * direction) * cell_size;
@@ -498,42 +425,18 @@ void main() {
float log2_diameter = log2(diameter);
vec4 scolor = textureLod(sampler3D(color_texture, texture_sampler), uvw_pos, log2_diameter);
-#ifdef MODE_ANISOTROPIC
-
- vec3 aniso_neg = textureLod(sampler3D(aniso_neg_texture, texture_sampler), uvw_pos, log2_diameter).rgb;
- vec3 aniso_pos = textureLod(sampler3D(aniso_pos_texture, texture_sampler), uvw_pos, log2_diameter).rgb;
-
- scolor.rgb *= dot(max(vec3(0.0), (aniso_normal * aniso_pos)), vec3(1.0)) + dot(max(vec3(0.0), (-aniso_normal * aniso_neg)), vec3(1.0));
-#endif
float a = (1.0 - color.a);
color += a * scolor;
dist += half_diameter;
}
}
color *= cone_weights[i] * vec4(albedo.rgb, 1.0) * params.dynamic_range; //restore range
-#ifdef MODE_ANISOTROPIC
- for (uint j = 0; j < 6; j++) {
- accum[j] += max(0.0, dot(accum_dirs[j], direction)) * color.rgb;
- }
-#else
accum += color.rgb;
-#endif
}
}
-#ifdef MODE_ANISOTROPIC
-
- outputs.data[cell_index * 6 + 0] = vec4(accum[0], 0.0);
- outputs.data[cell_index * 6 + 1] = vec4(accum[1], 0.0);
- outputs.data[cell_index * 6 + 2] = vec4(accum[2], 0.0);
- outputs.data[cell_index * 6 + 3] = vec4(accum[3], 0.0);
- outputs.data[cell_index * 6 + 4] = vec4(accum[4], 0.0);
- outputs.data[cell_index * 6 + 5] = vec4(accum[5], 0.0);
-#else
outputs.data[cell_index] = vec4(accum, 0.0);
-#endif
-
#endif // MODE_SECOND_BOUNCE
/////////////////UPDATE MIPMAPS///////////////////////////////
@@ -541,45 +444,20 @@ void main() {
#ifdef MODE_UPDATE_MIPMAPS
{
-#ifdef MODE_ANISOTROPIC
- vec3 light_accum[6] = vec3[](vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
-#else
vec3 light_accum = vec3(0.0);
-#endif
float count = 0.0;
for (uint i = 0; i < 8; i++) {
uint child_index = cell_children.data[cell_index].children[i];
if (child_index == NO_CHILDREN) {
continue;
}
-#ifdef MODE_ANISOTROPIC
- light_accum[0] += outputs.data[child_index * 6 + 0].rgb;
- light_accum[1] += outputs.data[child_index * 6 + 1].rgb;
- light_accum[2] += outputs.data[child_index * 6 + 2].rgb;
- light_accum[3] += outputs.data[child_index * 6 + 3].rgb;
- light_accum[4] += outputs.data[child_index * 6 + 4].rgb;
- light_accum[5] += outputs.data[child_index * 6 + 5].rgb;
-
-#else
light_accum += outputs.data[child_index].rgb;
-#endif
-
count += 1.0;
}
float divisor = mix(8.0, count, params.propagation);
-#ifdef MODE_ANISOTROPIC
- outputs.data[cell_index * 6 + 0] = vec4(light_accum[0] / divisor, 0.0);
- outputs.data[cell_index * 6 + 1] = vec4(light_accum[1] / divisor, 0.0);
- outputs.data[cell_index * 6 + 2] = vec4(light_accum[2] / divisor, 0.0);
- outputs.data[cell_index * 6 + 3] = vec4(light_accum[3] / divisor, 0.0);
- outputs.data[cell_index * 6 + 4] = vec4(light_accum[4] / divisor, 0.0);
- outputs.data[cell_index * 6 + 5] = vec4(light_accum[5] / divisor, 0.0);
-
-#else
outputs.data[cell_index] = vec4(light_accum / divisor, 0.0);
-#endif
}
#endif
@@ -587,40 +465,7 @@ void main() {
#ifdef MODE_WRITE_TEXTURE
{
-#ifdef MODE_ANISOTROPIC
- vec3 accum_total = vec3(0.0);
- accum_total += outputs.data[cell_index * 6 + 0].rgb;
- accum_total += outputs.data[cell_index * 6 + 1].rgb;
- accum_total += outputs.data[cell_index * 6 + 2].rgb;
- accum_total += outputs.data[cell_index * 6 + 3].rgb;
- accum_total += outputs.data[cell_index * 6 + 4].rgb;
- accum_total += outputs.data[cell_index * 6 + 5].rgb;
-
- float accum_total_energy = max(dot(accum_total, GREY_VEC), 0.00001);
- vec3 iso_positive = vec3(dot(outputs.data[cell_index * 6 + 0].rgb, GREY_VEC), dot(outputs.data[cell_index * 6 + 2].rgb, GREY_VEC), dot(outputs.data[cell_index * 6 + 4].rgb, GREY_VEC)) / vec3(accum_total_energy);
- vec3 iso_negative = vec3(dot(outputs.data[cell_index * 6 + 1].rgb, GREY_VEC), dot(outputs.data[cell_index * 6 + 3].rgb, GREY_VEC), dot(outputs.data[cell_index * 6 + 5].rgb, GREY_VEC)) / vec3(accum_total_energy);
-
- {
- uint aniso_pos = uint(clamp(iso_positive.b * 31.0, 0.0, 31.0));
- aniso_pos |= uint(clamp(iso_positive.g * 63.0, 0.0, 63.0)) << 5;
- aniso_pos |= uint(clamp(iso_positive.r * 31.0, 0.0, 31.0)) << 11;
- imageStore(aniso_pos_tex, ivec3(posu), uvec4(aniso_pos));
- }
-
- {
- uint aniso_neg = uint(clamp(iso_negative.b * 31.0, 0.0, 31.0));
- aniso_neg |= uint(clamp(iso_negative.g * 63.0, 0.0, 63.0)) << 5;
- aniso_neg |= uint(clamp(iso_negative.r * 31.0, 0.0, 31.0)) << 11;
- imageStore(aniso_neg_tex, ivec3(posu), uvec4(aniso_neg));
- }
-
- imageStore(color_tex, ivec3(posu), vec4(accum_total / params.dynamic_range, albedo.a));
-
-#else
-
imageStore(color_tex, ivec3(posu), vec4(outputs.data[cell_index].rgb / params.dynamic_range, albedo.a));
-
-#endif
}
#endif
@@ -763,13 +608,6 @@ void main() {
color.rgb /= params.dynamic_range;
imageStore(color_texture, pos3d, color);
//imageStore(color_texture,pos3d,vec4(1,1,1,1));
-
-#ifdef MODE_ANISOTROPIC
- //do not care about anisotropy for dynamic objects, just store full lit in all directions
- imageStore(aniso_pos_texture, pos3d, uvec4(0xFFFF));
- imageStore(aniso_neg_texture, pos3d, uvec4(0xFFFF));
-
-#endif // ANISOTROPIC
}
#endif // MODE_DYNAMIC_SHRINK_PLOT
}
diff --git a/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl
index 7d4d72967a..281c496df3 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl
+++ b/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl
@@ -20,11 +20,6 @@ layout(set = 0, binding = 2) uniform texture3D color_tex;
layout(set = 0, binding = 3) uniform sampler tex_sampler;
-#ifdef USE_ANISOTROPY
-layout(set = 0, binding = 4) uniform texture3D aniso_pos_tex;
-layout(set = 0, binding = 5) uniform texture3D aniso_neg_tex;
-#endif
-
layout(push_constant, binding = 0, std430) uniform Params {
mat4 projection;
uint cell_offset;
diff --git a/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl
index e20b3f680d..e20b3f680d 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl
+++ b/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl
diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h
index db1e3d1377..02c845581c 100644
--- a/servers/rendering/renderer_scene.h
+++ b/servers/rendering/renderer_scene.h
@@ -42,7 +42,7 @@ public:
virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) = 0;
virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) = 0;
virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) = 0;
- virtual void camera_set_transform(RID p_camera, const Transform &p_transform) = 0;
+ virtual void camera_set_transform(RID p_camera, const Transform3D &p_transform) = 0;
virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers) = 0;
virtual void camera_set_environment(RID p_camera, RID p_env) = 0;
virtual void camera_set_camera_effects(RID p_camera, RID p_fx) = 0;
@@ -56,13 +56,14 @@ public:
virtual RID scenario_allocate() = 0;
virtual void scenario_initialize(RID p_rid) = 0;
- virtual void scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode) = 0;
virtual void scenario_set_environment(RID p_scenario, RID p_environment) = 0;
virtual void scenario_set_camera_effects(RID p_scenario, RID p_fx) = 0;
virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment) = 0;
virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) = 0;
virtual bool is_scenario(RID p_scenario) const = 0;
virtual RID scenario_get_environment(RID p_scenario) = 0;
+ virtual void scenario_add_viewport_visibility_mask(RID p_scenario, RID p_viewport) = 0;
+ virtual void scenario_remove_viewport_visibility_mask(RID p_scenario, RID p_viewport) = 0;
virtual RID instance_allocate() = 0;
virtual void instance_initialize(RID p_rid) = 0;
@@ -70,18 +71,21 @@ public:
virtual void instance_set_base(RID p_instance, RID p_base) = 0;
virtual void instance_set_scenario(RID p_instance, RID p_scenario) = 0;
virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask) = 0;
- virtual void instance_set_transform(RID p_instance, const Transform &p_transform) = 0;
+ virtual void instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0;
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0;
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0;
virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) = 0;
virtual void instance_set_visible(RID p_instance, bool p_visible) = 0;
+ virtual void instance_geometry_set_transparency(RID p_instance, float p_transparency) = 0;
virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb) = 0;
virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton) = 0;
- virtual void instance_set_exterior(RID p_instance, bool p_enabled) = 0;
virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) = 0;
+ virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance) = 0;
+
+ virtual void instance_set_ignore_culling(RID p_instance, bool p_enabled) = 0;
// don't use these in a game!
virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0;
@@ -92,11 +96,9 @@ public:
virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) = 0;
virtual void instance_geometry_set_material_override(RID p_instance, RID p_material) = 0;
- virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0;
- virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) = 0;
+ virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin, RS::VisibilityRangeFadeMode p_fade_mode) = 0;
virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) = 0;
virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0;
-
virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) = 0;
virtual void instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const = 0;
virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const = 0;
@@ -126,13 +128,13 @@ public:
virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0;
virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0;
virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0;
- virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0;
+ virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) = 0;
virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0;
virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0;
virtual void environment_glow_set_use_high_quality(bool p_enable) = 0;
- virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) = 0;
+ virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) = 0;
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0;
virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0;
@@ -189,23 +191,31 @@ public:
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, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) = 0;
+ virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0;
virtual void gi_set_use_half_resolution(bool p_enable) = 0;
virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0;
virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) = 0;
- virtual void gi_probe_set_quality(RS::GIProbeQuality) = 0;
+ virtual void voxel_gi_set_quality(RS::VoxelGIQuality) = 0;
virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0;
virtual void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) = 0;
- virtual void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0;
- virtual void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0;
+
+ struct RenderInfo {
+ int info[RS::VIEWPORT_RENDER_INFO_TYPE_MAX][RS::VIEWPORT_RENDER_INFO_MAX] = {};
+ };
+
+ virtual void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RenderInfo *r_render_info = nullptr) = 0;
virtual void update() = 0;
virtual void render_probes() = 0;
+ virtual void update_visibility_notifiers() = 0;
+
+ virtual void decals_set_filter(RS::DecalFilter p_filter) = 0;
+ virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) = 0;
virtual bool free(RID p_rid) = 0;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index fcea8e4ffc..5b834db178 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -43,11 +43,11 @@ RID RendererSceneCull::camera_allocate() {
return camera_owner.allocate_rid();
}
void RendererSceneCull::camera_initialize(RID p_rid) {
- camera_owner.initialize_rid(p_rid, memnew(Camera));
+ camera_owner.initialize_rid(p_rid);
}
void RendererSceneCull::camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) {
- Camera *camera = camera_owner.getornull(p_camera);
+ Camera *camera = camera_owner.get_or_null(p_camera);
ERR_FAIL_COND(!camera);
camera->type = Camera::PERSPECTIVE;
camera->fov = p_fovy_degrees;
@@ -56,7 +56,7 @@ void RendererSceneCull::camera_set_perspective(RID p_camera, float p_fovy_degree
}
void RendererSceneCull::camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) {
- Camera *camera = camera_owner.getornull(p_camera);
+ Camera *camera = camera_owner.get_or_null(p_camera);
ERR_FAIL_COND(!camera);
camera->type = Camera::ORTHOGONAL;
camera->size = p_size;
@@ -65,7 +65,7 @@ void RendererSceneCull::camera_set_orthogonal(RID p_camera, float p_size, float
}
void RendererSceneCull::camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) {
- Camera *camera = camera_owner.getornull(p_camera);
+ Camera *camera = camera_owner.get_or_null(p_camera);
ERR_FAIL_COND(!camera);
camera->type = Camera::FRUSTUM;
camera->size = p_size;
@@ -74,33 +74,33 @@ void RendererSceneCull::camera_set_frustum(RID p_camera, float p_size, Vector2 p
camera->zfar = p_z_far;
}
-void RendererSceneCull::camera_set_transform(RID p_camera, const Transform &p_transform) {
- Camera *camera = camera_owner.getornull(p_camera);
+void RendererSceneCull::camera_set_transform(RID p_camera, const Transform3D &p_transform) {
+ Camera *camera = camera_owner.get_or_null(p_camera);
ERR_FAIL_COND(!camera);
camera->transform = p_transform.orthonormalized();
}
void RendererSceneCull::camera_set_cull_mask(RID p_camera, uint32_t p_layers) {
- Camera *camera = camera_owner.getornull(p_camera);
+ Camera *camera = camera_owner.get_or_null(p_camera);
ERR_FAIL_COND(!camera);
camera->visible_layers = p_layers;
}
void RendererSceneCull::camera_set_environment(RID p_camera, RID p_env) {
- Camera *camera = camera_owner.getornull(p_camera);
+ Camera *camera = camera_owner.get_or_null(p_camera);
ERR_FAIL_COND(!camera);
camera->env = p_env;
}
void RendererSceneCull::camera_set_camera_effects(RID p_camera, RID p_fx) {
- Camera *camera = camera_owner.getornull(p_camera);
+ Camera *camera = camera_owner.get_or_null(p_camera);
ERR_FAIL_COND(!camera);
camera->effects = p_fx;
}
void RendererSceneCull::camera_set_use_vertical_aspect(RID p_camera, bool p_enable) {
- Camera *camera = camera_owner.getornull(p_camera);
+ Camera *camera = camera_owner.get_or_null(p_camera);
ERR_FAIL_COND(!camera);
camera->vaspect = p_enable;
}
@@ -151,6 +151,22 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
idata.flags |= InstanceData::FLAG_GEOM_LIGHTING_DIRTY;
}
+ if (light->uses_projector) {
+ geom->projector_count++;
+ if (geom->projector_count == 1) {
+ InstanceData &idata = A->scenario->instance_data[A->array_index];
+ idata.flags |= InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY;
+ }
+ }
+
+ if (light->uses_softshadow) {
+ geom->softshadow_count++;
+ if (geom->softshadow_count == 1) {
+ InstanceData &idata = A->scenario->instance_data[A->array_index];
+ idata.flags |= InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY;
+ }
+ }
+
} else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data);
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
@@ -190,26 +206,26 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
((RendererSceneCull *)self)->_instance_queue_update(A, false, false); //need to update capture
}
- } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_GI_PROBE) && B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
+ } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_VOXEL_GI) && B->base_type == RS::INSTANCE_VOXEL_GI && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data);
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
- geom->gi_probes.insert(B);
+ geom->voxel_gi_instances.insert(B);
if (A->dynamic_gi) {
- gi_probe->dynamic_geometries.insert(A);
+ voxel_gi->dynamic_geometries.insert(A);
} else {
- gi_probe->geometries.insert(A);
+ voxel_gi->geometries.insert(A);
}
if (A->scenario && A->array_index >= 0) {
InstanceData &idata = A->scenario->instance_data[A->array_index];
- idata.flags |= InstanceData::FLAG_GEOM_GI_PROBE_DIRTY;
+ idata.flags |= InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY;
}
- } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
- gi_probe->lights.insert(A);
+ } else if (B->base_type == RS::INSTANCE_VOXEL_GI && A->base_type == RS::INSTANCE_LIGHT) {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data);
+ voxel_gi->lights.insert(A);
} else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) {
InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(B->base_data);
RSG::storage->particles_add_collision(A->base, collision->instance);
@@ -242,6 +258,32 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) {
idata.flags |= InstanceData::FLAG_GEOM_LIGHTING_DIRTY;
}
+ if (light->uses_projector) {
+#ifdef DEBUG_ENABLED
+ if (geom->projector_count == 0) {
+ ERR_PRINT("geom->projector_count==0 - BUG!");
+ }
+#endif
+ geom->projector_count--;
+ if (geom->projector_count == 0) {
+ InstanceData &idata = A->scenario->instance_data[A->array_index];
+ idata.flags |= InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY;
+ }
+ }
+
+ if (light->uses_softshadow) {
+#ifdef DEBUG_ENABLED
+ if (geom->softshadow_count == 0) {
+ ERR_PRINT("geom->softshadow_count==0 - BUG!");
+ }
+#endif
+ geom->softshadow_count--;
+ if (geom->softshadow_count == 0) {
+ InstanceData &idata = A->scenario->instance_data[A->array_index];
+ idata.flags |= InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY;
+ }
+ }
+
} else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data);
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
@@ -281,25 +323,25 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) {
((RendererSceneCull *)self)->_instance_queue_update(A, false, false); //need to update capture
}
- } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_GI_PROBE) && B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
+ } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_VOXEL_GI) && B->base_type == RS::INSTANCE_VOXEL_GI && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data);
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
- geom->gi_probes.erase(B);
+ geom->voxel_gi_instances.erase(B);
if (A->dynamic_gi) {
- gi_probe->dynamic_geometries.erase(A);
+ voxel_gi->dynamic_geometries.erase(A);
} else {
- gi_probe->geometries.erase(A);
+ voxel_gi->geometries.erase(A);
}
if (A->scenario && A->array_index >= 0) {
InstanceData &idata = A->scenario->instance_data[A->array_index];
- idata.flags |= InstanceData::FLAG_GEOM_GI_PROBE_DIRTY;
+ idata.flags |= InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY;
}
- } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
- gi_probe->lights.erase(A);
+ } else if (B->base_type == RS::INSTANCE_VOXEL_GI && A->base_type == RS::INSTANCE_LIGHT) {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data);
+ voxel_gi->lights.erase(A);
} else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) {
InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(B->base_data);
RSG::storage->particles_remove_collision(A->base, collision->instance);
@@ -310,7 +352,9 @@ RID RendererSceneCull::scenario_allocate() {
return scenario_owner.allocate_rid();
}
void RendererSceneCull::scenario_initialize(RID p_rid) {
- Scenario *scenario = memnew(Scenario);
+ scenario_owner.initialize_rid(p_rid);
+
+ Scenario *scenario = scenario_owner.get_or_null(p_rid);
scenario->self = p_rid;
scenario->reflection_probe_shadow_atlas = scene_render->shadow_atlas_create();
@@ -323,38 +367,31 @@ void RendererSceneCull::scenario_initialize(RID p_rid) {
scenario->instance_aabbs.set_page_pool(&instance_aabb_page_pool);
scenario->instance_data.set_page_pool(&instance_data_page_pool);
+ scenario->instance_visibility.set_page_pool(&instance_visibility_data_page_pool);
RendererSceneOcclusionCull::get_singleton()->add_scenario(p_rid);
-
- scenario_owner.initialize_rid(p_rid, scenario);
-}
-
-void RendererSceneCull::scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode) {
- Scenario *scenario = scenario_owner.getornull(p_scenario);
- ERR_FAIL_COND(!scenario);
- scenario->debug = p_debug_mode;
}
void RendererSceneCull::scenario_set_environment(RID p_scenario, RID p_environment) {
- Scenario *scenario = scenario_owner.getornull(p_scenario);
+ Scenario *scenario = scenario_owner.get_or_null(p_scenario);
ERR_FAIL_COND(!scenario);
scenario->environment = p_environment;
}
void RendererSceneCull::scenario_set_camera_effects(RID p_scenario, RID p_camera_effects) {
- Scenario *scenario = scenario_owner.getornull(p_scenario);
+ Scenario *scenario = scenario_owner.get_or_null(p_scenario);
ERR_FAIL_COND(!scenario);
scenario->camera_effects = p_camera_effects;
}
void RendererSceneCull::scenario_set_fallback_environment(RID p_scenario, RID p_environment) {
- Scenario *scenario = scenario_owner.getornull(p_scenario);
+ Scenario *scenario = scenario_owner.get_or_null(p_scenario);
ERR_FAIL_COND(!scenario);
scenario->fallback_environment = p_environment;
}
void RendererSceneCull::scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) {
- Scenario *scenario = scenario_owner.getornull(p_scenario);
+ Scenario *scenario = scenario_owner.get_or_null(p_scenario);
ERR_FAIL_COND(!scenario);
scene_render->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count);
}
@@ -364,11 +401,42 @@ bool RendererSceneCull::is_scenario(RID p_scenario) const {
}
RID RendererSceneCull::scenario_get_environment(RID p_scenario) {
- Scenario *scenario = scenario_owner.getornull(p_scenario);
+ Scenario *scenario = scenario_owner.get_or_null(p_scenario);
ERR_FAIL_COND_V(!scenario, RID());
return scenario->environment;
}
+void RendererSceneCull::scenario_remove_viewport_visibility_mask(RID p_scenario, RID p_viewport) {
+ Scenario *scenario = scenario_owner.get_or_null(p_scenario);
+ ERR_FAIL_COND(!scenario);
+ if (!scenario->viewport_visibility_masks.has(p_viewport)) {
+ return;
+ }
+
+ uint64_t mask = scenario->viewport_visibility_masks[p_viewport];
+ scenario->used_viewport_visibility_bits &= ~mask;
+ scenario->viewport_visibility_masks.erase(p_viewport);
+}
+
+void RendererSceneCull::scenario_add_viewport_visibility_mask(RID p_scenario, RID p_viewport) {
+ Scenario *scenario = scenario_owner.get_or_null(p_scenario);
+ ERR_FAIL_COND(!scenario);
+ ERR_FAIL_COND(scenario->viewport_visibility_masks.has(p_viewport));
+
+ uint64_t new_mask = 1;
+ while (new_mask & scenario->used_viewport_visibility_bits) {
+ new_mask <<= 1;
+ }
+
+ if (new_mask == 0) {
+ ERR_PRINT("Only 64 viewports per scenario allowed when using visibility ranges.");
+ new_mask = ((uint64_t)1) << 63;
+ }
+
+ scenario->viewport_visibility_masks[p_viewport] = new_mask;
+ scenario->used_viewport_visibility_bits |= new_mask;
+}
+
/* INSTANCING API */
void RendererSceneCull::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) {
@@ -390,10 +458,9 @@ RID RendererSceneCull::instance_allocate() {
return instance_owner.allocate_rid();
}
void RendererSceneCull::instance_initialize(RID p_rid) {
- Instance *instance = memnew(Instance);
+ instance_owner.initialize_rid(p_rid);
+ Instance *instance = instance_owner.get_or_null(p_rid);
instance->self = p_rid;
-
- instance_owner.initialize_rid(p_rid, instance);
}
void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) {
@@ -426,7 +493,7 @@ void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) {
}
void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
Scenario *scenario = instance->scenario;
@@ -447,7 +514,6 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
switch (instance->base_type) {
case RS::INSTANCE_MESH:
case RS::INSTANCE_MULTIMESH:
- case RS::INSTANCE_IMMEDIATE:
case RS::INSTANCE_PARTICLES: {
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
scene_render->geometry_instance_free(geom->geometry_instance);
@@ -474,6 +540,13 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data);
RSG::storage->free(collision->instance);
} break;
+ case RS::INSTANCE_FOG_VOLUME: {
+ InstanceFogVolumeData *volume = static_cast<InstanceFogVolumeData *>(instance->base_data);
+ scene_render->free(volume->instance);
+ } break;
+ case RS::INSTANCE_VISIBLITY_NOTIFIER: {
+ //none
+ } break;
case RS::INSTANCE_REFLECTION_PROBE: {
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data);
scene_render->free(reflection_probe->instance);
@@ -494,23 +567,23 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
}
scene_render->free(lightmap_data->instance);
} break;
- case RS::INSTANCE_GI_PROBE: {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data);
+ case RS::INSTANCE_VOXEL_GI: {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(instance->base_data);
#ifdef DEBUG_ENABLED
- if (gi_probe->geometries.size()) {
- ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe.");
+ if (voxel_gi->geometries.size()) {
+ ERR_PRINT("BUG, indexing did not unpair geometries from VoxelGI.");
}
#endif
#ifdef DEBUG_ENABLED
- if (gi_probe->lights.size()) {
- ERR_PRINT("BUG, indexing did not unpair lights from GIProbe.");
+ if (voxel_gi->lights.size()) {
+ ERR_PRINT("BUG, indexing did not unpair lights from VoxelGI.");
}
#endif
- if (gi_probe->update_element.in_list()) {
- gi_probe_update_list.remove(&gi_probe->update_element);
+ if (voxel_gi->update_element.in_list()) {
+ voxel_gi_update_list.remove(&voxel_gi->update_element);
}
- scene_render->free(gi_probe->probe_instance);
+ scene_render->free(voxel_gi->probe_instance);
} break;
case RS::INSTANCE_OCCLUDER: {
@@ -556,7 +629,6 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
} break;
case RS::INSTANCE_MESH:
case RS::INSTANCE_MULTIMESH:
- case RS::INSTANCE_IMMEDIATE:
case RS::INSTANCE_PARTICLES: {
InstanceGeometryData *geom = memnew(InstanceGeometryData);
instance->base_data = geom;
@@ -572,10 +644,17 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
scene_render->geometry_instance_set_use_dynamic_gi(geom->geometry_instance, instance->dynamic_gi);
scene_render->geometry_instance_set_cast_double_sided_shadows(geom->geometry_instance, instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED);
scene_render->geometry_instance_set_use_lightmap(geom->geometry_instance, RID(), instance->lightmap_uv_scale, instance->lightmap_slice_index);
+ scene_render->geometry_instance_set_transparency(geom->geometry_instance, instance->transparency);
if (instance->lightmap_sh.size() == 9) {
scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, instance->lightmap_sh.ptr());
}
+ for (Set<Instance *>::Element *E = instance->visibility_dependencies.front(); E; E = E->next()) {
+ Instance *dep_instance = E->get();
+ ERR_CONTINUE(dep_instance->array_index == -1);
+ ERR_CONTINUE(dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index != -1);
+ dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = instance->array_index;
+ }
} break;
case RS::INSTANCE_PARTICLES_COLLISION: {
InstanceParticlesCollisionData *collision = memnew(InstanceParticlesCollisionData);
@@ -583,6 +662,17 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
RSG::storage->particles_collision_instance_set_active(collision->instance, instance->visible);
instance->base_data = collision;
} break;
+ case RS::INSTANCE_FOG_VOLUME: {
+ InstanceFogVolumeData *volume = memnew(InstanceFogVolumeData);
+ volume->instance = scene_render->fog_volume_instance_create(p_base);
+ scene_render->fog_volume_instance_set_active(volume->instance, instance->visible);
+ instance->base_data = volume;
+ } break;
+ case RS::INSTANCE_VISIBLITY_NOTIFIER: {
+ InstanceVisibilityNotifierData *vnd = memnew(InstanceVisibilityNotifierData);
+ vnd->base = p_base;
+ instance->base_data = vnd;
+ } break;
case RS::INSTANCE_REFLECTION_PROBE: {
InstanceReflectionProbeData *reflection_probe = memnew(InstanceReflectionProbeData);
reflection_probe->owner = instance;
@@ -602,16 +692,16 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
instance->base_data = lightmap_data;
lightmap_data->instance = scene_render->lightmap_instance_create(p_base);
} break;
- case RS::INSTANCE_GI_PROBE: {
- InstanceGIProbeData *gi_probe = memnew(InstanceGIProbeData);
- instance->base_data = gi_probe;
- gi_probe->owner = instance;
+ case RS::INSTANCE_VOXEL_GI: {
+ InstanceVoxelGIData *voxel_gi = memnew(InstanceVoxelGIData);
+ instance->base_data = voxel_gi;
+ voxel_gi->owner = instance;
- if (scenario && !gi_probe->update_element.in_list()) {
- gi_probe_update_list.add(&gi_probe->update_element);
+ if (scenario && !voxel_gi->update_element.in_list()) {
+ voxel_gi_update_list.add(&voxel_gi->update_element);
}
- gi_probe->probe_instance = scene_render->gi_probe_instance_create(p_base);
+ voxel_gi->probe_instance = scene_render->voxel_gi_instance_create(p_base);
} break;
case RS::INSTANCE_OCCLUDER: {
@@ -637,7 +727,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
}
void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
if (instance->scenario) {
@@ -668,22 +758,22 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
case RS::INSTANCE_PARTICLES_COLLISION: {
heightfield_particle_colliders_update_list.erase(instance);
} break;
- case RS::INSTANCE_GI_PROBE: {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data);
+ case RS::INSTANCE_VOXEL_GI: {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(instance->base_data);
#ifdef DEBUG_ENABLED
- if (gi_probe->geometries.size()) {
- ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe.");
+ if (voxel_gi->geometries.size()) {
+ ERR_PRINT("BUG, indexing did not unpair geometries from VoxelGI.");
}
#endif
#ifdef DEBUG_ENABLED
- if (gi_probe->lights.size()) {
- ERR_PRINT("BUG, indexing did not unpair lights from GIProbe.");
+ if (voxel_gi->lights.size()) {
+ ERR_PRINT("BUG, indexing did not unpair lights from VoxelGI.");
}
#endif
- if (gi_probe->update_element.in_list()) {
- gi_probe_update_list.remove(&gi_probe->update_element);
+ if (voxel_gi->update_element.in_list()) {
+ voxel_gi_update_list.remove(&voxel_gi->update_element);
}
} break;
case RS::INSTANCE_OCCLUDER: {
@@ -699,7 +789,7 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
}
if (p_scenario.is_valid()) {
- Scenario *scenario = scenario_owner.getornull(p_scenario);
+ Scenario *scenario = scenario_owner.get_or_null(p_scenario);
ERR_FAIL_COND(!scenario);
instance->scenario = scenario;
@@ -714,10 +804,10 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
light->D = scenario->directional_lights.push_back(instance);
}
} break;
- case RS::INSTANCE_GI_PROBE: {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data);
- if (!gi_probe->update_element.in_list()) {
- gi_probe_update_list.add(&gi_probe->update_element);
+ case RS::INSTANCE_VOXEL_GI: {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(instance->base_data);
+ if (!voxel_gi->update_element.in_list()) {
+ voxel_gi_update_list.add(&voxel_gi->update_element);
}
} break;
case RS::INSTANCE_OCCLUDER: {
@@ -732,7 +822,7 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
}
void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
instance->layer_mask = p_mask;
@@ -746,8 +836,20 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask)
}
}
-void RendererSceneCull::instance_set_transform(RID p_instance, const Transform &p_transform) {
- Instance *instance = instance_owner.getornull(p_instance);
+void RendererSceneCull::instance_geometry_set_transparency(RID p_instance, float p_transparency) {
+ Instance *instance = instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ instance->transparency = p_transparency;
+
+ if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ scene_render->geometry_instance_set_transparency(geom->geometry_instance, p_transparency);
+ }
+}
+
+void RendererSceneCull::instance_set_transform(RID p_instance, const Transform3D &p_transform) {
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
if (instance->transform == p_transform) {
@@ -772,14 +874,14 @@ void RendererSceneCull::instance_set_transform(RID p_instance, const Transform &
}
void RendererSceneCull::instance_attach_object_instance_id(RID p_instance, ObjectID p_id) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
instance->object_id = p_id;
}
void RendererSceneCull::instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
if (instance->update_item.in_list()) {
@@ -792,7 +894,7 @@ void RendererSceneCull::instance_set_blend_shape_weight(RID p_instance, int p_sh
}
void RendererSceneCull::instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
if (instance->base_type == RS::INSTANCE_MESH) {
@@ -808,7 +910,7 @@ void RendererSceneCull::instance_set_surface_override_material(RID p_instance, i
}
void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
if (instance->visible == p_visible) {
@@ -841,6 +943,11 @@ void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) {
RSG::storage->particles_collision_instance_set_active(collision->instance, p_visible);
}
+ if (instance->base_type == RS::INSTANCE_FOG_VOLUME) {
+ InstanceFogVolumeData *volume = static_cast<InstanceFogVolumeData *>(instance->base_data);
+ scene_render->fog_volume_instance_set_active(volume->instance, p_visible);
+ }
+
if (instance->base_type == RS::INSTANCE_OCCLUDER) {
if (instance->scenario) {
RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(instance->scenario->self, p_instance, instance->base, instance->transform, p_visible);
@@ -849,11 +956,11 @@ void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) {
}
inline bool is_geometry_instance(RenderingServer::InstanceType p_type) {
- return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_PARTICLES || p_type == RS::INSTANCE_IMMEDIATE;
+ return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_PARTICLES;
}
void RendererSceneCull::instance_set_custom_aabb(RID p_instance, AABB p_aabb) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
ERR_FAIL_COND(!is_geometry_instance(instance->base_type));
@@ -878,7 +985,7 @@ void RendererSceneCull::instance_set_custom_aabb(RID p_instance, AABB p_aabb) {
}
void RendererSceneCull::instance_attach_skeleton(RID p_instance, RID p_skeleton) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
if (instance->skeleton == p_skeleton) {
@@ -902,20 +1009,32 @@ void RendererSceneCull::instance_attach_skeleton(RID p_instance, RID p_skeleton)
}
}
-void RendererSceneCull::instance_set_exterior(RID p_instance, bool p_enabled) {
-}
-
void RendererSceneCull::instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
instance->extra_margin = p_margin;
_instance_queue_update(instance, true, false);
}
+void RendererSceneCull::instance_set_ignore_culling(RID p_instance, bool p_enabled) {
+ Instance *instance = instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND(!instance);
+ instance->ignore_all_culling = p_enabled;
+
+ if (instance->scenario && instance->array_index >= 0) {
+ InstanceData &idata = instance->scenario->instance_data[instance->array_index];
+ if (instance->ignore_all_culling) {
+ idata.flags |= InstanceData::FLAG_IGNORE_ALL_CULLING;
+ } else {
+ idata.flags &= ~uint32_t(InstanceData::FLAG_IGNORE_ALL_CULLING);
+ }
+ }
+}
+
Vector<ObjectID> RendererSceneCull::instances_cull_aabb(const AABB &p_aabb, RID p_scenario) const {
Vector<ObjectID> instances;
- Scenario *scenario = scenario_owner.getornull(p_scenario);
+ Scenario *scenario = scenario_owner.get_or_null(p_scenario);
ERR_FAIL_COND_V(!scenario, instances);
const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling
@@ -939,7 +1058,7 @@ Vector<ObjectID> RendererSceneCull::instances_cull_aabb(const AABB &p_aabb, RID
Vector<ObjectID> RendererSceneCull::instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const {
Vector<ObjectID> instances;
- Scenario *scenario = scenario_owner.getornull(p_scenario);
+ Scenario *scenario = scenario_owner.get_or_null(p_scenario);
ERR_FAIL_COND_V(!scenario, instances);
const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling
@@ -962,7 +1081,7 @@ Vector<ObjectID> RendererSceneCull::instances_cull_ray(const Vector3 &p_from, co
Vector<ObjectID> RendererSceneCull::instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario) const {
Vector<ObjectID> instances;
- Scenario *scenario = scenario_owner.getornull(p_scenario);
+ Scenario *scenario = scenario_owner.get_or_null(p_scenario);
ERR_FAIL_COND_V(!scenario, instances);
const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling
@@ -986,7 +1105,7 @@ Vector<ObjectID> RendererSceneCull::instances_cull_convex(const Vector<Plane> &p
}
void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
//ERR_FAIL_COND(((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK));
@@ -1061,7 +1180,7 @@ void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceF
}
void RendererSceneCull::instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
instance->cast_shadows = p_shadow_casting_setting;
@@ -1069,7 +1188,7 @@ void RendererSceneCull::instance_geometry_set_cast_shadows_setting(RID p_instanc
if (instance->scenario && instance->array_index >= 0) {
InstanceData &idata = instance->scenario->instance_data[instance->array_index];
- if (instance->cast_shadows != RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) {
+ if (instance->cast_shadows != RS::SHADOW_CASTING_SETTING_OFF) {
idata.flags |= InstanceData::FLAG_CAST_SHADOWS;
} else {
idata.flags &= ~uint32_t(InstanceData::FLAG_CAST_SHADOWS);
@@ -1091,7 +1210,7 @@ void RendererSceneCull::instance_geometry_set_cast_shadows_setting(RID p_instanc
}
void RendererSceneCull::instance_geometry_set_material_override(RID p_instance, RID p_material) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
instance->material_override = p_material;
@@ -1103,14 +1222,150 @@ void RendererSceneCull::instance_geometry_set_material_override(RID p_instance,
}
}
-void RendererSceneCull::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) {
+void RendererSceneCull::instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin, RS::VisibilityRangeFadeMode p_fade_mode) {
+ Instance *instance = instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ instance->visibility_range_begin = p_min;
+ instance->visibility_range_end = p_max;
+ instance->visibility_range_begin_margin = p_min_margin;
+ instance->visibility_range_end_margin = p_max_margin;
+ instance->visibility_range_fade_mode = p_fade_mode;
+
+ _update_instance_visibility_dependencies(instance);
+
+ if (instance->scenario && instance->visibility_index != -1) {
+ InstanceVisibilityData &vd = instance->scenario->instance_visibility[instance->visibility_index];
+ vd.range_begin = instance->visibility_range_begin;
+ vd.range_end = instance->visibility_range_end;
+ vd.range_begin_margin = instance->visibility_range_begin_margin;
+ vd.range_end_margin = instance->visibility_range_end_margin;
+ vd.fade_mode = p_fade_mode;
+ }
}
-void RendererSceneCull::instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) {
+void RendererSceneCull::instance_set_visibility_parent(RID p_instance, RID p_parent_instance) {
+ Instance *instance = instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ Instance *old_parent = instance->visibility_parent;
+ if (old_parent) {
+ old_parent->visibility_dependencies.erase(instance);
+ instance->visibility_parent = nullptr;
+ _update_instance_visibility_depth(old_parent);
+ }
+
+ Instance *parent = instance_owner.get_or_null(p_parent_instance);
+ ERR_FAIL_COND(p_parent_instance.is_valid() && !parent);
+
+ if (parent) {
+ parent->visibility_dependencies.insert(instance);
+ instance->visibility_parent = parent;
+
+ bool cycle_detected = _update_instance_visibility_depth(parent);
+ if (cycle_detected) {
+ ERR_PRINT("Cycle detected in the visibility dependencies tree. The latest change to visibility_parent will have no effect.");
+ parent->visibility_dependencies.erase(instance);
+ instance->visibility_parent = nullptr;
+ }
+ }
+
+ _update_instance_visibility_dependencies(instance);
+}
+
+bool RendererSceneCull::_update_instance_visibility_depth(Instance *p_instance) {
+ bool cycle_detected = false;
+ Set<Instance *> traversed_nodes;
+
+ {
+ Instance *instance = p_instance;
+ while (instance) {
+ if (!instance->visibility_dependencies.is_empty()) {
+ uint32_t depth = 0;
+ for (Set<Instance *>::Element *E = instance->visibility_dependencies.front(); E; E = E->next()) {
+ depth = MAX(depth, E->get()->visibility_dependencies_depth);
+ }
+ instance->visibility_dependencies_depth = depth + 1;
+ } else {
+ instance->visibility_dependencies_depth = 0;
+ }
+
+ if (instance->scenario && instance->visibility_index != -1) {
+ instance->scenario->instance_visibility.move(instance->visibility_index, instance->visibility_dependencies_depth);
+ }
+
+ traversed_nodes.insert(instance);
+
+ instance = instance->visibility_parent;
+ if (traversed_nodes.has(instance)) {
+ cycle_detected = true;
+ break;
+ }
+ }
+ }
+
+ return cycle_detected;
+}
+
+void RendererSceneCull::_update_instance_visibility_dependencies(Instance *p_instance) {
+ bool is_geometry_instance = ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) && p_instance->base_data;
+ bool has_visibility_range = p_instance->visibility_range_begin > 0.0 || p_instance->visibility_range_end > 0.0;
+ bool needs_visibility_cull = has_visibility_range && is_geometry_instance && p_instance->array_index != -1;
+
+ if (!needs_visibility_cull && p_instance->visibility_index != -1) {
+ p_instance->scenario->instance_visibility.remove_at(p_instance->visibility_index);
+ p_instance->visibility_index = -1;
+ } else if (needs_visibility_cull && p_instance->visibility_index == -1) {
+ InstanceVisibilityData vd;
+ vd.instance = p_instance;
+ vd.range_begin = p_instance->visibility_range_begin;
+ vd.range_end = p_instance->visibility_range_end;
+ vd.range_begin_margin = p_instance->visibility_range_begin_margin;
+ vd.range_end_margin = p_instance->visibility_range_end_margin;
+ vd.position = p_instance->transformed_aabb.get_center();
+ vd.array_index = p_instance->array_index;
+ vd.fade_mode = p_instance->visibility_range_fade_mode;
+
+ p_instance->scenario->instance_visibility.insert(vd, p_instance->visibility_dependencies_depth);
+ }
+
+ if (p_instance->scenario && p_instance->array_index != -1) {
+ InstanceData &idata = p_instance->scenario->instance_data[p_instance->array_index];
+ idata.visibility_index = p_instance->visibility_index;
+
+ if (is_geometry_instance) {
+ if (has_visibility_range && p_instance->visibility_range_fade_mode == RS::VISIBILITY_RANGE_FADE_SELF) {
+ bool begin_enabled = p_instance->visibility_range_begin > 0.0f;
+ float begin_min = p_instance->visibility_range_begin - p_instance->visibility_range_begin_margin;
+ float begin_max = p_instance->visibility_range_begin + p_instance->visibility_range_begin_margin;
+ bool end_enabled = p_instance->visibility_range_end > 0.0f;
+ float end_min = p_instance->visibility_range_end - p_instance->visibility_range_end_margin;
+ float end_max = p_instance->visibility_range_end + p_instance->visibility_range_end_margin;
+ scene_render->geometry_instance_set_fade_range(idata.instance_geometry, begin_enabled, begin_min, begin_max, end_enabled, end_min, end_max);
+ } else {
+ scene_render->geometry_instance_set_fade_range(idata.instance_geometry, false, 0.0f, 0.0f, false, 0.0f, 0.0f);
+ }
+ }
+
+ if ((has_visibility_range || p_instance->visibility_parent) && (p_instance->visibility_index == -1 || p_instance->visibility_dependencies_depth == 0)) {
+ idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK;
+ } else {
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK;
+ }
+
+ if (p_instance->visibility_parent) {
+ idata.parent_array_index = p_instance->visibility_parent->array_index;
+ } else {
+ idata.parent_array_index = -1;
+ if (is_geometry_instance) {
+ scene_render->geometry_instance_set_parent_fade_alpha(idata.instance_geometry, 1.0f);
+ }
+ }
+ }
}
void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
if (instance->lightmap) {
@@ -1119,7 +1374,7 @@ void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lig
instance->lightmap = nullptr;
}
- Instance *lightmap_instance = instance_owner.getornull(p_lightmap);
+ Instance *lightmap_instance = instance_owner.get_or_null(p_lightmap);
instance->lightmap = lightmap_instance;
instance->lightmap_uv_scale = p_lightmap_uv_scale;
@@ -1140,7 +1395,7 @@ void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lig
}
void RendererSceneCull::instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
instance->lod_bias = p_lod_bias;
@@ -1152,9 +1407,11 @@ void RendererSceneCull::instance_geometry_set_lod_bias(RID p_instance, float p_l
}
void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) {
- Instance *instance = instance_owner.getornull(p_instance);
+ Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
+ ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT);
+
Map<StringName, Instance::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.find(p_parameter);
if (!E) {
@@ -1173,7 +1430,7 @@ void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, c
}
Variant RendererSceneCull::instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const {
- const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.getornull(p_instance);
+ const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!instance, Variant());
if (instance->instance_shader_parameters.has(p_parameter)) {
@@ -1183,7 +1440,7 @@ Variant RendererSceneCull::instance_geometry_get_shader_parameter(RID p_instance
}
Variant RendererSceneCull::instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const {
- const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.getornull(p_instance);
+ const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!instance, Variant());
if (instance->instance_shader_parameters.has(p_parameter)) {
@@ -1193,14 +1450,14 @@ Variant RendererSceneCull::instance_geometry_get_shader_parameter_default_value(
}
void RendererSceneCull::instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const {
- const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.getornull(p_instance);
+ const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
const_cast<RendererSceneCull *>(this)->update_dirty_instances();
Vector<StringName> names;
- for (Map<StringName, Instance::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.front(); E; E = E->next()) {
- names.push_back(E->key());
+ for (const KeyValue<StringName, Instance::InstanceShaderParameter> &E : instance->instance_shader_parameters) {
+ names.push_back(E.key);
}
names.sort_custom<StringName::AlphCompare>();
for (int i = 0; i < names.size(); i++) {
@@ -1253,10 +1510,10 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
InstanceLightmapData *lightmap = static_cast<InstanceLightmapData *>(p_instance->base_data);
scene_render->lightmap_instance_set_transform(lightmap->instance, p_instance->transform);
- } else if (p_instance->base_type == RS::INSTANCE_GI_PROBE) {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(p_instance->base_data);
+ } else if (p_instance->base_type == RS::INSTANCE_VOXEL_GI) {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(p_instance->base_data);
- scene_render->gi_probe_instance_set_transform_to_data(gi_probe->probe_instance, p_instance->transform);
+ scene_render->voxel_gi_instance_set_transform_to_data(voxel_gi->probe_instance, p_instance->transform);
} else if (p_instance->base_type == RS::INSTANCE_PARTICLES) {
RSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform);
} else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) {
@@ -1267,6 +1524,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
heightfield_particle_colliders_update_list.insert(p_instance);
}
RSG::storage->particles_collision_instance_set_transform(collision->instance, p_instance->transform);
+ } else if (p_instance->base_type == RS::INSTANCE_FOG_VOLUME) {
+ InstanceFogVolumeData *volume = static_cast<InstanceFogVolumeData *>(p_instance->base_data);
+ scene_render->fog_volume_instance_set_transform(volume->instance, p_instance->transform);
} else if (p_instance->base_type == RS::INSTANCE_OCCLUDER) {
if (p_instance->scenario) {
RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(p_instance->scenario->self, p_instance->self, p_instance->base, p_instance->transform, p_instance->visible);
@@ -1352,15 +1612,29 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
idata.layer_mask = p_instance->layer_mask;
idata.flags = p_instance->base_type; //changing it means de-indexing, so this never needs to be changed later
idata.base_rid = p_instance->base;
+ idata.parent_array_index = p_instance->visibility_parent ? p_instance->visibility_parent->array_index : -1;
+ idata.visibility_index = p_instance->visibility_index;
+
+ for (Set<Instance *>::Element *E = p_instance->visibility_dependencies.front(); E; E = E->next()) {
+ Instance *dep_instance = E->get();
+ if (dep_instance->array_index != -1) {
+ dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = p_instance->array_index;
+ }
+ }
+
switch (p_instance->base_type) {
case RS::INSTANCE_MESH:
case RS::INSTANCE_MULTIMESH:
- case RS::INSTANCE_IMMEDIATE:
case RS::INSTANCE_PARTICLES: {
- idata.instance_geometry = static_cast<InstanceGeometryData *>(p_instance->base_data)->geometry_instance;
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data);
+ idata.instance_geometry = geom->geometry_instance;
} break;
case RS::INSTANCE_LIGHT: {
- idata.instance_data_rid = static_cast<InstanceLightData *>(p_instance->base_data)->instance.get_id();
+ InstanceLightData *light_data = static_cast<InstanceLightData *>(p_instance->base_data);
+ idata.instance_data_rid = light_data->instance.get_id();
+ light_data->uses_projector = RSG::storage->light_has_projector(p_instance->base);
+ light_data->uses_softshadow = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SIZE) > CMP_EPSILON;
+
} break;
case RS::INSTANCE_REFLECTION_PROBE: {
idata.instance_data_rid = static_cast<InstanceReflectionProbeData *>(p_instance->base_data)->instance.get_id();
@@ -1371,8 +1645,14 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
case RS::INSTANCE_LIGHTMAP: {
idata.instance_data_rid = static_cast<InstanceLightmapData *>(p_instance->base_data)->instance.get_id();
} break;
- case RS::INSTANCE_GI_PROBE: {
- idata.instance_data_rid = static_cast<InstanceGIProbeData *>(p_instance->base_data)->probe_instance.get_id();
+ case RS::INSTANCE_VOXEL_GI: {
+ idata.instance_data_rid = static_cast<InstanceVoxelGIData *>(p_instance->base_data)->probe_instance.get_id();
+ } break;
+ case RS::INSTANCE_FOG_VOLUME: {
+ idata.instance_data_rid = static_cast<InstanceFogVolumeData *>(p_instance->base_data)->instance.get_id();
+ } break;
+ case RS::INSTANCE_VISIBLITY_NOTIFIER: {
+ idata.visibility_notifier = static_cast<InstanceVisibilityNotifierData *>(p_instance->base_data);
} break;
default: {
}
@@ -1382,7 +1662,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
//always dirty when added
idata.flags |= InstanceData::FLAG_REFLECTION_PROBE_DIRTY;
}
- if (p_instance->cast_shadows != RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) {
+ if (p_instance->cast_shadows != RS::SHADOW_CASTING_SETTING_OFF) {
idata.flags |= InstanceData::FLAG_CAST_SHADOWS;
}
if (p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) {
@@ -1401,9 +1681,13 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
if (p_instance->ignore_occlusion_culling) {
idata.flags |= InstanceData::FLAG_IGNORE_OCCLUSION_CULLING;
}
+ if (p_instance->ignore_all_culling) {
+ idata.flags |= InstanceData::FLAG_IGNORE_ALL_CULLING;
+ }
p_instance->scenario->instance_data.push_back(idata);
p_instance->scenario->instance_aabbs.push_back(InstanceBounds(p_instance->transformed_aabb));
+ _update_instance_visibility_dependencies(p_instance);
} else {
if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].update(p_instance->indexer_id, bvh_aabb);
@@ -1413,6 +1697,10 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
p_instance->scenario->instance_aabbs[p_instance->array_index] = InstanceBounds(p_instance->transformed_aabb);
}
+ if (p_instance->visibility_index != -1) {
+ p_instance->scenario->instance_visibility[p_instance->visibility_index].position = p_instance->transformed_aabb.get_center();
+ }
+
//move instance and repair
pair_pass++;
@@ -1425,7 +1713,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
pair.pair_mask |= 1 << RS::INSTANCE_LIGHT;
- pair.pair_mask |= 1 << RS::INSTANCE_GI_PROBE;
+ pair.pair_mask |= 1 << RS::INSTANCE_VOXEL_GI;
pair.pair_mask |= 1 << RS::INSTANCE_LIGHTMAP;
if (p_instance->base_type == RS::INSTANCE_PARTICLES) {
pair.pair_mask |= 1 << RS::INSTANCE_PARTICLES_COLLISION;
@@ -1439,7 +1727,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];
if (RSG::storage->light_get_bake_mode(p_instance->base) == RS::LIGHT_BAKE_DYNAMIC) {
- pair.pair_mask |= (1 << RS::INSTANCE_GI_PROBE);
+ pair.pair_mask |= (1 << RS::INSTANCE_VOXEL_GI);
pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES];
}
} else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE)) {
@@ -1451,7 +1739,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
} else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) {
pair.pair_mask = (1 << RS::INSTANCE_PARTICLES);
pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];
- } else if (p_instance->base_type == RS::INSTANCE_GI_PROBE) {
+ } else if (p_instance->base_type == RS::INSTANCE_VOXEL_GI) {
//lights and geometries
pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT);
pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];
@@ -1486,9 +1774,21 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) {
//replace this by last
int32_t swap_with_index = p_instance->scenario->instance_data.size() - 1;
if (swap_with_index != p_instance->array_index) {
- p_instance->scenario->instance_data[swap_with_index].instance->array_index = p_instance->array_index; //swap
+ Instance *swapped_instance = p_instance->scenario->instance_data[swap_with_index].instance;
+ swapped_instance->array_index = p_instance->array_index; //swap
p_instance->scenario->instance_data[p_instance->array_index] = p_instance->scenario->instance_data[swap_with_index];
p_instance->scenario->instance_aabbs[p_instance->array_index] = p_instance->scenario->instance_aabbs[swap_with_index];
+
+ if (swapped_instance->visibility_index != -1) {
+ swapped_instance->scenario->instance_visibility[swapped_instance->visibility_index].array_index = swapped_instance->array_index;
+ }
+
+ for (Set<Instance *>::Element *E = swapped_instance->visibility_dependencies.front(); E; E = E->next()) {
+ Instance *dep_instance = E->get();
+ if (dep_instance != p_instance && dep_instance->array_index != -1) {
+ dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = swapped_instance->array_index;
+ }
+ }
}
// pop last
@@ -1504,8 +1804,20 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) {
scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, nullptr, 0);
scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, nullptr, 0);
scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, nullptr, 0);
- scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, nullptr, 0);
+ scene_render->geometry_instance_pair_voxel_gi_instances(geom->geometry_instance, nullptr, 0);
+ }
+
+ for (Set<Instance *>::Element *E = p_instance->visibility_dependencies.front(); E; E = E->next()) {
+ Instance *dep_instance = E->get();
+ if (dep_instance->array_index != -1) {
+ dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = -1;
+ if ((1 << dep_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
+ scene_render->geometry_instance_set_parent_fade_alpha(dep_instance->scenario->instance_data[dep_instance->array_index].instance_geometry, 1.0f);
+ }
+ }
}
+
+ _update_instance_visibility_dependencies(p_instance);
}
void RendererSceneCull::_update_instance_aabb(Instance *p_instance) {
@@ -1534,14 +1846,6 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) {
}
} break;
- case RenderingServer::INSTANCE_IMMEDIATE: {
- if (p_instance->custom_aabb) {
- new_aabb = *p_instance->custom_aabb;
- } else {
- new_aabb = RSG::storage->immediate_get_aabb(p_instance->base);
- }
-
- } break;
case RenderingServer::INSTANCE_PARTICLES: {
if (p_instance->custom_aabb) {
new_aabb = *p_instance->custom_aabb;
@@ -1554,6 +1858,12 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) {
new_aabb = RSG::storage->particles_collision_get_aabb(p_instance->base);
} break;
+ case RenderingServer::INSTANCE_FOG_VOLUME: {
+ new_aabb = RSG::storage->fog_volume_get_aabb(p_instance->base);
+ } break;
+ case RenderingServer::INSTANCE_VISIBLITY_NOTIFIER: {
+ new_aabb = RSG::storage->visibility_notifier_get_aabb(p_instance->base);
+ } break;
case RenderingServer::INSTANCE_LIGHT: {
new_aabb = RSG::storage->light_get_aabb(p_instance->base);
@@ -1566,8 +1876,8 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) {
new_aabb = RSG::storage->decal_get_aabb(p_instance->base);
} break;
- case RenderingServer::INSTANCE_GI_PROBE: {
- new_aabb = RSG::storage->gi_probe_get_bounds(p_instance->base);
+ case RenderingServer::INSTANCE_VOXEL_GI: {
+ new_aabb = RSG::storage->voxel_gi_get_bounds(p_instance->base);
} break;
case RenderingServer::INSTANCE_LIGHTMAP: {
@@ -1605,8 +1915,8 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance)
continue; //we are inside, ignore exteriors
}
- Transform to_bounds = lightmap->transform.affine_inverse();
- Vector3 center = p_instance->transform.xform(p_instance->aabb.position + p_instance->aabb.size * 0.5); //use aabb center
+ Transform3D to_bounds = lightmap->transform.affine_inverse();
+ Vector3 center = p_instance->transform.xform(p_instance->aabb.get_center()); //use aabb center
Vector3 lm_pos = to_bounds.xform(center);
@@ -1621,7 +1931,7 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance)
//rotate it
Basis rot = lightmap->transform.basis.orthonormalized();
for (int i = 0; i < 3; i++) {
- float csh[9];
+ real_t csh[9];
for (int j = 0; j < 9; j++) {
csh[j] = sh[j][i];
}
@@ -1633,7 +1943,7 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance)
Vector3 inner_pos = ((lm_pos - bounds.position) / bounds.size) * 2.0 - Vector3(1.0, 1.0, 1.0);
- float blend = MAX(inner_pos.x, MAX(inner_pos.y, inner_pos.z));
+ real_t blend = MAX(inner_pos.x, MAX(inner_pos.y, inner_pos.z));
//make blend more rounded
blend = Math::lerp(inner_pos.length(), blend, blend);
blend *= blend;
@@ -1666,10 +1976,10 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance)
scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, p_instance->lightmap_sh.ptr());
}
-void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect) {
+void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform3D p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect) {
InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
- Transform light_transform = p_instance->transform;
+ Transform3D light_transform = p_instance->transform;
light_transform.orthonormalize(); //scale does not count on lights
real_t max_distance = p_cam_projection.get_z_far();
@@ -1680,8 +1990,6 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
max_distance = MAX(max_distance, p_cam_projection.get_z_near() + 0.001);
real_t min_distance = MIN(p_cam_projection.get_z_near(), max_distance);
- RS::LightDirectionalShadowDepthRangeMode depth_range_mode = RSG::storage->light_directional_get_shadow_depth_range_mode(p_instance->base);
-
real_t pancake_size = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE);
real_t range = max_distance - min_distance;
@@ -1712,10 +2020,6 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
bool overlap = RSG::storage->light_directional_get_blend_splits(p_instance->base);
- real_t first_radius = 0.0;
-
- real_t min_distance_bias_scale = distances[1];
-
cull.shadow_count = p_shadow_index + 1;
cull.shadows[p_shadow_index].cascade_count = splits;
cull.shadows[p_shadow_index].light_instance = light->instance;
@@ -1745,7 +2049,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
// obtain the light frustum ranges (given endpoints)
- Transform transform = light_transform; //discard scale and stabilize light
+ Transform3D transform = light_transform; //discard scale and stabilize light
Vector3 x_vec = transform.basis.get_axis(Vector3::AXIS_X).normalized();
Vector3 y_vec = transform.basis.get_axis(Vector3::AXIS_Y).normalized();
@@ -1763,8 +2067,8 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
real_t z_min_cam = 0.f;
//real_t z_max_cam = 0.f;
- real_t bias_scale = 1.0;
- real_t aspect_bias_scale = 1.0;
+ //real_t bias_scale = 1.0;
+ //real_t aspect_bias_scale = 1.0;
//used for culling
@@ -1818,12 +2122,6 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
radius *= texture_size / (texture_size - 2.0); //add a texel by each side
- if (i == 0) {
- first_radius = radius;
- } else {
- bias_scale = radius / first_radius;
- }
-
z_min_cam = z_vec.dot(center) - radius;
{
@@ -1841,22 +2139,13 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
}
}
- 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
-
- real_t unit = radius * 2.0 / texture_size;
-
- x_max_cam = Math::snapped(x_max_cam, unit);
- x_min_cam = Math::snapped(x_min_cam, unit);
- y_max_cam = Math::snapped(y_max_cam, unit);
- y_min_cam = Math::snapped(y_min_cam, unit);
- }
+ // 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.
+ const real_t unit = (radius + soft_shadow_expand) * 2.0 / texture_size;
+ x_max_cam = Math::snapped(x_vec.dot(center) + radius + soft_shadow_expand, unit);
+ x_min_cam = Math::snapped(x_vec.dot(center) - radius - soft_shadow_expand, unit);
+ y_max_cam = Math::snapped(y_vec.dot(center) + radius + soft_shadow_expand, unit);
+ y_min_cam = Math::snapped(y_vec.dot(center) - radius - soft_shadow_expand, unit);
}
//now that we know all ranges, we can proceed to make the light frustum planes, for culling octree
@@ -1876,64 +2165,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
// a pre pass will need to be needed to determine the actual z-near to be used
- if (pancake_size > 0) {
- z_max = z_vec.dot(center) + radius + pancake_size;
- }
-
- if (aspect != 1.0) {
- // if the aspect is different, then the radius will become larger.
- // if this happens, then bias needs to be adjusted too, as depth will increase
- // to do this, compare the depth of one that would have resulted from a square frustum
-
- CameraMatrix camera_matrix_square;
- if (p_cam_orthogonal) {
- Vector2 vp_he = camera_matrix.get_viewport_half_extents();
- if (p_cam_vaspect) {
- camera_matrix_square.set_orthogonal(vp_he.x * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true);
- } else {
- camera_matrix_square.set_orthogonal(vp_he.y * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false);
- }
- } else {
- Vector2 vp_he = camera_matrix.get_viewport_half_extents();
- if (p_cam_vaspect) {
- camera_matrix_square.set_frustum(vp_he.x * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true);
- } else {
- camera_matrix_square.set_frustum(vp_he.y * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false);
- }
- }
-
- Vector3 endpoints_square[8]; // frustum plane endpoints
- res = camera_matrix_square.get_endpoints(p_cam_transform, endpoints_square);
- ERR_CONTINUE(!res);
- Vector3 center_square;
-
- for (int j = 0; j < 8; j++) {
- center_square += endpoints_square[j];
- }
-
- center_square /= 8.0;
-
- real_t radius_square = 0;
-
- for (int j = 0; j < 8; j++) {
- real_t d = center_square.distance_to(endpoints_square[j]);
- if (d > radius_square) {
- radius_square = d;
- }
- }
-
- radius_square *= texture_size / (texture_size - 2.0); //add a texel by each side
-
- float z_max_square = z_vec.dot(center_square) + radius_square + pancake_size;
-
- real_t z_min_cam_square = z_vec.dot(center_square) - radius_square;
-
- aspect_bias_scale = (z_max - z_min_cam) / (z_max_square - z_min_cam_square);
-
- // this is not entirely perfect, because the cull-adjusted z-max may be different
- // but at least it's warranted that it results in a greater bias, so no acne should be present either way.
- // pancaking also helps with this.
- }
+ z_max = z_vec.dot(center) + radius + pancake_size;
{
CameraMatrix ortho_camera;
@@ -1944,7 +2176,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
Vector2 uv_scale(1.0 / (x_max_cam - x_min_cam), 1.0 / (y_max_cam - y_min_cam));
- Transform ortho_transform;
+ Transform3D 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;
@@ -1954,17 +2186,17 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
cull.shadows[p_shadow_index].cascades[i].zfar = z_max - z_min_cam;
cull.shadows[p_shadow_index].cascades[i].split = distances[i + 1];
cull.shadows[p_shadow_index].cascades[i].shadow_texel_size = radius * 2.0 / texture_size;
- cull.shadows[p_shadow_index].cascades[i].bias_scale = bias_scale * aspect_bias_scale * min_distance_bias_scale;
+ cull.shadows[p_shadow_index].cascades[i].bias_scale = (z_max - z_min_cam);
cull.shadows[p_shadow_index].cascades[i].range_begin = z_max;
cull.shadows[p_shadow_index].cascades[i].uv_scale = uv_scale;
}
}
}
-bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_screen_lod_threshold) {
+bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, const Transform3D p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_screen_lod_threshold) {
InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
- Transform light_transform = p_instance->transform;
+ Transform3D light_transform = p_instance->transform;
light_transform.orthonormalize(); //scale does not count on lights
bool animated_material_found = false;
@@ -2013,8 +2245,6 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex);
- Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z);
-
RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++];
for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) {
@@ -2048,7 +2278,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE);
CameraMatrix cm;
- cm.set_perspective(90, 1, 0.01, radius);
+ cm.set_perspective(90, 1, radius * 0.005f, radius);
for (int i = 0; i < 6; i++) {
RENDER_TIMESTAMP("Culling Shadow Cube side" + itos(i));
@@ -2071,7 +2301,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
Vector3(0, -1, 0)
};
- Transform xform = light_transform * Transform().looking_at(view_normals[i], view_up[i]);
+ Transform3D xform = light_transform * Transform3D().looking_at(view_normals[i], view_up[i]);
Vector<Plane> planes = cm.get_projection_planes(xform);
@@ -2134,7 +2364,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
real_t angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SPOT_ANGLE);
CameraMatrix cm;
- cm.set_perspective(angle * 2.0, 1.0, 0.01, radius);
+ cm.set_perspective(angle * 2.0, 1.0, 0.005f * radius, radius);
Vector<Plane> planes = cm.get_projection_planes(light_transform);
@@ -2186,153 +2416,198 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
return animated_material_found;
}
-void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) {
-// render to mono camera
+void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RenderInfo *r_render_info) {
#ifndef _3D_DISABLED
- Camera *camera = camera_owner.getornull(p_camera);
+ Camera *camera = camera_owner.get_or_null(p_camera);
ERR_FAIL_COND(!camera);
- /* STEP 1 - SETUP CAMERA */
- CameraMatrix camera_matrix;
- bool ortho = false;
-
- switch (camera->type) {
- case Camera::ORTHOGONAL: {
- camera_matrix.set_orthogonal(
- camera->size,
- p_viewport_size.width / (float)p_viewport_size.height,
- camera->znear,
- camera->zfar,
- camera->vaspect);
- ortho = true;
- } break;
- case Camera::PERSPECTIVE: {
- camera_matrix.set_perspective(
- camera->fov,
- p_viewport_size.width / (float)p_viewport_size.height,
- camera->znear,
- camera->zfar,
- camera->vaspect);
- ortho = false;
+ RendererSceneRender::CameraData camera_data;
+
+ // Setup Camera(s)
+ if (p_xr_interface.is_null()) {
+ // Normal camera
+ Transform3D transform = camera->transform;
+ CameraMatrix projection;
+ bool vaspect = camera->vaspect;
+ bool is_ortogonal = false;
+
+ switch (camera->type) {
+ case Camera::ORTHOGONAL: {
+ projection.set_orthogonal(
+ camera->size,
+ p_viewport_size.width / (float)p_viewport_size.height,
+ camera->znear,
+ camera->zfar,
+ camera->vaspect);
+ is_ortogonal = true;
+ } break;
+ case Camera::PERSPECTIVE: {
+ projection.set_perspective(
+ camera->fov,
+ p_viewport_size.width / (float)p_viewport_size.height,
+ camera->znear,
+ camera->zfar,
+ camera->vaspect);
- } break;
- case Camera::FRUSTUM: {
- camera_matrix.set_frustum(
- camera->size,
- p_viewport_size.width / (float)p_viewport_size.height,
- camera->offset,
- camera->znear,
- camera->zfar,
- camera->vaspect);
- ortho = false;
- } break;
+ } break;
+ case Camera::FRUSTUM: {
+ projection.set_frustum(
+ camera->size,
+ p_viewport_size.width / (float)p_viewport_size.height,
+ camera->offset,
+ camera->znear,
+ camera->zfar,
+ camera->vaspect);
+ } break;
+ }
+
+ camera_data.set_camera(transform, projection, is_ortogonal, vaspect);
+ } else {
+ // Setup our camera for our XR interface.
+ // We can support multiple views here each with their own camera
+ Transform3D transforms[RendererSceneRender::MAX_RENDER_VIEWS];
+ CameraMatrix projections[RendererSceneRender::MAX_RENDER_VIEWS];
+
+ uint32_t view_count = p_xr_interface->get_view_count();
+ ERR_FAIL_COND_MSG(view_count > RendererSceneRender::MAX_RENDER_VIEWS, "Requested view count is not supported");
+
+ float aspect = p_viewport_size.width / (float)p_viewport_size.height;
+
+ Transform3D world_origin = XRServer::get_singleton()->get_world_origin();
+
+ // We ignore our camera position, it will have been positioned with a slightly old tracking position.
+ // Instead we take our origin point and have our XR interface add fresh tracking data! Whoohoo!
+ for (uint32_t v = 0; v < view_count; v++) {
+ transforms[v] = p_xr_interface->get_transform_for_view(v, world_origin);
+ projections[v] = p_xr_interface->get_projection_for_view(v, aspect, camera->znear, camera->zfar);
+ }
+
+ if (view_count == 1) {
+ camera_data.set_camera(transforms[0], projections[0], false, camera->vaspect);
+ } else if (view_count == 2) {
+ camera_data.set_multiview_camera(view_count, transforms, projections, false, camera->vaspect);
+ } else {
+ // this won't be called (see fail check above) but keeping this comment to indicate we may support more then 2 views in the future...
+ }
}
RID environment = _render_get_environment(p_camera, p_scenario);
RENDER_TIMESTAMP("Update occlusion buffer")
- RendererSceneOcclusionCull::get_singleton()->buffer_update(p_viewport, camera->transform, camera_matrix, ortho, RendererThreadPool::singleton->thread_work_pool);
+ // For now just cull on the first camera
+ RendererSceneOcclusionCull::get_singleton()->buffer_update(p_viewport, camera_data.main_transform, camera_data.main_projection, camera_data.is_ortogonal, RendererThreadPool::singleton->thread_work_pool);
- _render_scene(camera->transform, camera_matrix, ortho, camera->vaspect, p_render_buffers, environment, camera->effects, camera->visible_layers, p_scenario, p_viewport, p_shadow_atlas, RID(), -1, p_screen_lod_threshold);
+ _render_scene(&camera_data, p_render_buffers, environment, camera->effects, camera->visible_layers, p_scenario, p_viewport, p_shadow_atlas, RID(), -1, p_screen_lod_threshold, true, r_render_info);
#endif
}
-void RendererSceneCull::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) {
- // render for AR/VR interface
-#if 0
- Camera *camera = camera_owner.getornull(p_camera);
- ERR_FAIL_COND(!camera);
+void RendererSceneCull::_visibility_cull_threaded(uint32_t p_thread, VisibilityCullData *cull_data) {
+ uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count();
+ uint32_t bin_from = p_thread * cull_data->cull_count / total_threads;
+ uint32_t bin_to = (p_thread + 1 == total_threads) ? cull_data->cull_count : ((p_thread + 1) * cull_data->cull_count / total_threads);
- /* SETUP CAMERA, we are ignoring type and FOV here */
- float aspect = p_viewport_size.width / (float)p_viewport_size.height;
- CameraMatrix camera_matrix = p_interface->get_projection_for_eye(p_eye, aspect, camera->znear, camera->zfar);
+ _visibility_cull(*cull_data, cull_data->cull_offset + bin_from, cull_data->cull_offset + bin_to);
+}
- // We also ignore our camera position, it will have been positioned with a slightly old tracking position.
- // Instead we take our origin point and have our ar/vr interface add fresh tracking data! Whoohoo!
- Transform world_origin = XRServer::get_singleton()->get_world_origin();
- Transform cam_transform = p_interface->get_transform_for_eye(p_eye, world_origin);
+void RendererSceneCull::_visibility_cull(const VisibilityCullData &cull_data, uint64_t p_from, uint64_t p_to) {
+ Scenario *scenario = cull_data.scenario;
+ for (unsigned int i = p_from; i < p_to; i++) {
+ InstanceVisibilityData &vd = scenario->instance_visibility[i];
+ InstanceData &idata = scenario->instance_data[vd.array_index];
- RID environment = _render_get_environment(p_camera, p_scenario);
+ if (idata.parent_array_index >= 0) {
+ uint32_t parent_flags = scenario->instance_data[idata.parent_array_index].flags;
- // For stereo render we only prepare for our left eye and then reuse the outcome for our right eye
- if (p_eye == XRInterface::EYE_LEFT) {
- // Center our transform, we assume basis is equal.
- Transform mono_transform = cam_transform;
- Transform right_transform = p_interface->get_transform_for_eye(XRInterface::EYE_RIGHT, world_origin);
- mono_transform.origin += right_transform.origin;
- mono_transform.origin *= 0.5;
-
- // We need to combine our projection frustums for culling.
- // Ideally we should use our clipping planes for this and combine them,
- // however our shadow map logic uses our projection matrix.
- // Note: as our left and right frustums should be mirrored, we don't need our right projection matrix.
-
- // - get some base values we need
- float eye_dist = (mono_transform.origin - cam_transform.origin).length();
- float z_near = camera_matrix.get_z_near(); // get our near plane
- float z_far = camera_matrix.get_z_far(); // get our far plane
- float width = (2.0 * z_near) / camera_matrix.matrix[0][0];
- float x_shift = width * camera_matrix.matrix[2][0];
- float height = (2.0 * z_near) / camera_matrix.matrix[1][1];
- float y_shift = height * camera_matrix.matrix[2][1];
-
- // printf("Eye_dist = %f, Near = %f, Far = %f, Width = %f, Shift = %f\n", eye_dist, z_near, z_far, width, x_shift);
-
- // - calculate our near plane size (horizontal only, right_near is mirrored)
- float left_near = -eye_dist - ((width - x_shift) * 0.5);
-
- // - calculate our far plane size (horizontal only, right_far is mirrored)
- float left_far = -eye_dist - (z_far * (width - x_shift) * 0.5 / z_near);
- float left_far_right_eye = eye_dist - (z_far * (width + x_shift) * 0.5 / z_near);
- if (left_far > left_far_right_eye) {
- // on displays smaller then double our iod, the right eye far frustrum can overtake the left eyes.
- left_far = left_far_right_eye;
- }
-
- // - figure out required z-shift
- float slope = (left_far - left_near) / (z_far - z_near);
- float z_shift = (left_near / slope) - z_near;
-
- // - figure out new vertical near plane size (this will be slightly oversized thanks to our z-shift)
- float top_near = (height - y_shift) * 0.5;
- top_near += (top_near / z_near) * z_shift;
- float bottom_near = -(height + y_shift) * 0.5;
- bottom_near += (bottom_near / z_near) * z_shift;
-
- // printf("Left_near = %f, Left_far = %f, Top_near = %f, Bottom_near = %f, Z_shift = %f\n", left_near, left_far, top_near, bottom_near, z_shift);
-
- // - generate our frustum
- CameraMatrix combined_matrix;
- combined_matrix.set_frustum(left_near, -left_near, bottom_near, top_near, z_near + z_shift, z_far + z_shift);
-
- // and finally move our camera back
- Transform apply_z_shift;
- apply_z_shift.origin = Vector3(0.0, 0.0, z_shift); // z negative is forward so this moves it backwards
- mono_transform *= apply_z_shift;
-
- // now prepare our scene with our adjusted transform projection matrix
- _prepare_scene(mono_transform, combined_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold);
- } else if (p_eye == XRInterface::EYE_MONO) {
- // For mono render, prepare as per usual
- _prepare_scene(cam_transform, camera_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold);
- }
-
- // And render our scene...
- _render_scene(p_render_buffers, cam_transform, camera_matrix, false, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1, p_screen_lod_threshold);
-#endif
-};
+ if ((parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN) || !(parent_flags & (InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE | InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN))) {
+ idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN;
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE;
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN;
+ continue;
+ }
+ }
+
+ int range_check = _visibility_range_check<true>(vd, cull_data.camera_position, cull_data.viewport_mask);
+
+ if (range_check == -1) {
+ idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN;
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE;
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN;
+ } else if (range_check == 1) {
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN;
+ idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE;
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN;
+ } else {
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN;
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE;
+ if (range_check == 2) {
+ idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN;
+ } else {
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN;
+ }
+ }
+ }
+}
+
+template <bool p_fade_check>
+int RendererSceneCull::_visibility_range_check(InstanceVisibilityData &r_vis_data, const Vector3 &p_camera_pos, uint64_t p_viewport_mask) {
+ float dist = p_camera_pos.distance_to(r_vis_data.position);
+ const RS::VisibilityRangeFadeMode &fade_mode = r_vis_data.fade_mode;
-void RendererSceneCull::_frustum_cull_threaded(uint32_t p_thread, CullData *cull_data) {
+ float begin_offset = -r_vis_data.range_begin_margin;
+ float end_offset = r_vis_data.range_end_margin;
+
+ if (fade_mode == RS::VISIBILITY_RANGE_FADE_DISABLED && !(p_viewport_mask & r_vis_data.viewport_state)) {
+ begin_offset = -begin_offset;
+ end_offset = -end_offset;
+ }
+
+ if (r_vis_data.range_end > 0.0f && dist > r_vis_data.range_end + end_offset) {
+ r_vis_data.viewport_state &= ~p_viewport_mask;
+ return -1;
+ } else if (r_vis_data.range_begin > 0.0f && dist < r_vis_data.range_begin + begin_offset) {
+ r_vis_data.viewport_state &= ~p_viewport_mask;
+ return 1;
+ } else {
+ r_vis_data.viewport_state |= p_viewport_mask;
+ if (p_fade_check) {
+ if (fade_mode != RS::VISIBILITY_RANGE_FADE_DISABLED) {
+ r_vis_data.children_fade_alpha = 1.0f;
+ if (r_vis_data.range_end > 0.0f && dist > r_vis_data.range_end - end_offset) {
+ if (fade_mode == RS::VISIBILITY_RANGE_FADE_DEPENDENCIES) {
+ r_vis_data.children_fade_alpha = MIN(1.0f, (dist - (r_vis_data.range_end - end_offset)) / (2.0f * r_vis_data.range_end_margin));
+ }
+ return 2;
+ } else if (r_vis_data.range_begin > 0.0f && dist < r_vis_data.range_begin - begin_offset) {
+ if (fade_mode == RS::VISIBILITY_RANGE_FADE_DEPENDENCIES) {
+ r_vis_data.children_fade_alpha = MIN(1.0f, 1.0 - (dist - (r_vis_data.range_begin + begin_offset)) / (2.0f * r_vis_data.range_begin_margin));
+ }
+ return 2;
+ }
+ }
+ }
+ return 0;
+ }
+}
+
+bool RendererSceneCull::_visibility_parent_check(const CullData &p_cull_data, const InstanceData &p_instance_data) {
+ if (p_instance_data.parent_array_index == -1) {
+ return true;
+ }
+ const uint32_t &parent_flags = p_cull_data.scenario->instance_data[p_instance_data.parent_array_index].flags;
+ return ((parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK) == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE) || (parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN);
+}
+
+void RendererSceneCull::_scene_cull_threaded(uint32_t p_thread, CullData *cull_data) {
uint32_t cull_total = cull_data->scenario->instance_data.size();
uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count();
uint32_t cull_from = p_thread * cull_total / total_threads;
uint32_t cull_to = (p_thread + 1 == total_threads) ? cull_total : ((p_thread + 1) * cull_total / total_threads);
- _frustum_cull(*cull_data, frustum_cull_result_threads[p_thread], cull_from, cull_to);
+ _scene_cull(*cull_data, scene_cull_result_threads[p_thread], cull_from, cull_to);
}
-void RendererSceneCull::_frustum_cull(CullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to) {
+void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cull_result, uint64_t p_from, uint64_t p_to) {
uint64_t frame_number = RSG::rasterizer->get_frame_number();
float lightmap_probe_update_speed = RSG::storage->lightmap_get_probe_capture_update_speed() * RSG::rasterizer->get_frame_delta_time();
@@ -2341,183 +2616,226 @@ void RendererSceneCull::_frustum_cull(CullData &cull_data, FrustumCullResult &cu
RID instance_pair_buffer[MAX_INSTANCE_PAIRS];
- Transform inv_cam_transform = cull_data.cam_transform.inverse();
+ Transform3D inv_cam_transform = cull_data.cam_transform.inverse();
float z_near = cull_data.camera_matrix->get_z_near();
for (uint64_t i = p_from; i < p_to; i++) {
bool mesh_visible = false;
- if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->frustum) && (cull_data.occlusion_buffer == nullptr || cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING ||
- !cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near))) {
- InstanceData &idata = cull_data.scenario->instance_data[i];
- uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
-
- if ((cull_data.visible_layers & idata.layer_mask) == 0) {
- //failure
- } else if (base_type == RS::INSTANCE_LIGHT) {
- cull_result.lights.push_back(idata.instance);
- cull_result.light_instances.push_back(RID::from_uint64(idata.instance_data_rid));
- if (cull_data.shadow_atlas.is_valid() && RSG::storage->light_has_shadow(idata.base_rid)) {
- scene_render->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later
- }
+ InstanceData &idata = cull_data.scenario->instance_data[i];
+ uint32_t visibility_flags = idata.flags & (InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE | InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN | InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN);
+ int32_t visibility_check = -1;
+
+#define HIDDEN_BY_VISIBILITY_CHECKS (visibility_flags == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE || visibility_flags == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN)
+#define LAYER_CHECK (cull_data.visible_layers & idata.layer_mask)
+#define IN_FRUSTUM(f) (cull_data.scenario->instance_aabbs[i].in_frustum(f))
+#define VIS_RANGE_CHECK ((idata.visibility_index == -1) || _visibility_range_check<false>(cull_data.scenario->instance_visibility[idata.visibility_index], cull_data.cam_transform.origin, cull_data.visibility_viewport_mask) == 0)
+#define VIS_PARENT_CHECK (_visibility_parent_check(cull_data, idata))
+#define VIS_CHECK (visibility_check < 0 ? (visibility_check = (visibility_flags != InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK || (VIS_RANGE_CHECK && VIS_PARENT_CHECK))) : visibility_check)
+#define OCCLUSION_CULLED (cull_data.occlusion_buffer != nullptr && (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING) == 0 && cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near))
- } else if (base_type == RS::INSTANCE_REFLECTION_PROBE) {
- if (cull_data.render_reflection_probe != idata.instance) {
- //avoid entering The Matrix
+ if (!HIDDEN_BY_VISIBILITY_CHECKS) {
+ if ((LAYER_CHECK && IN_FRUSTUM(cull_data.cull->frustum) && VIS_CHECK && !OCCLUSION_CULLED) || (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_ALL_CULLING)) {
+ uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
+ if (base_type == RS::INSTANCE_LIGHT) {
+ cull_result.lights.push_back(idata.instance);
+ cull_result.light_instances.push_back(RID::from_uint64(idata.instance_data_rid));
+ if (cull_data.shadow_atlas.is_valid() && RSG::storage->light_has_shadow(idata.base_rid)) {
+ scene_render->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later
+ }
+
+ } else if (base_type == RS::INSTANCE_REFLECTION_PROBE) {
+ if (cull_data.render_reflection_probe != idata.instance) {
+ //avoid entering The Matrix
+
+ if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || scene_render->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) {
+ InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(idata.instance->base_data);
+ cull_data.cull->lock.lock();
+ if (!reflection_probe->update_list.in_list()) {
+ reflection_probe->render_step = 0;
+ reflection_probe_render_list.add_last(&reflection_probe->update_list);
+ }
+ cull_data.cull->lock.unlock();
- if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || scene_render->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) {
- InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(idata.instance->base_data);
- cull_data.cull->lock.lock();
- if (!reflection_probe->update_list.in_list()) {
- reflection_probe->render_step = 0;
- reflection_probe_render_list.add_last(&reflection_probe->update_list);
+ idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY);
}
- cull_data.cull->lock.unlock();
- idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY);
+ if (scene_render->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) {
+ cull_result.reflections.push_back(RID::from_uint64(idata.instance_data_rid));
+ }
}
-
- if (scene_render->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) {
- cull_result.reflections.push_back(RID::from_uint64(idata.instance_data_rid));
+ } else if (base_type == RS::INSTANCE_DECAL) {
+ cull_result.decals.push_back(RID::from_uint64(idata.instance_data_rid));
+
+ } else if (base_type == RS::INSTANCE_VOXEL_GI) {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(idata.instance->base_data);
+ cull_data.cull->lock.lock();
+ if (!voxel_gi->update_element.in_list()) {
+ voxel_gi_update_list.add(&voxel_gi->update_element);
}
- }
- } else if (base_type == RS::INSTANCE_DECAL) {
- cull_result.decals.push_back(RID::from_uint64(idata.instance_data_rid));
-
- } else if (base_type == RS::INSTANCE_GI_PROBE) {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(idata.instance->base_data);
- cull_data.cull->lock.lock();
- if (!gi_probe->update_element.in_list()) {
- gi_probe_update_list.add(&gi_probe->update_element);
- }
- cull_data.cull->lock.unlock();
- cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid));
+ cull_data.cull->lock.unlock();
+ cull_result.voxel_gi_instances.push_back(RID::from_uint64(idata.instance_data_rid));
+
+ } else if (base_type == RS::INSTANCE_LIGHTMAP) {
+ cull_result.lightmaps.push_back(RID::from_uint64(idata.instance_data_rid));
+ } else if (base_type == RS::INSTANCE_FOG_VOLUME) {
+ cull_result.fog_volumes.push_back(RID::from_uint64(idata.instance_data_rid));
+ } else if (base_type == RS::INSTANCE_VISIBLITY_NOTIFIER) {
+ InstanceVisibilityNotifierData *vnd = idata.visibility_notifier;
+ if (!vnd->list_element.in_list()) {
+ visible_notifier_list_lock.lock();
+ visible_notifier_list.add(&vnd->list_element);
+ visible_notifier_list_lock.unlock();
+ vnd->just_visible = true;
+ }
+ vnd->visible_in_frame = RSG::rasterizer->get_frame_number();
+ } else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) {
+ bool keep = true;
- } else if (base_type == RS::INSTANCE_LIGHTMAP) {
- cull_result.lightmaps.push_back(RID::from_uint64(idata.instance_data_rid));
- } else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) {
- bool keep = true;
+ if (idata.flags & InstanceData::FLAG_REDRAW_IF_VISIBLE) {
+ RenderingServerDefault::redraw_request();
+ }
- if (idata.flags & InstanceData::FLAG_REDRAW_IF_VISIBLE) {
- RenderingServerDefault::redraw_request();
- }
+ if (base_type == RS::INSTANCE_MESH) {
+ mesh_visible = true;
+ } else if (base_type == RS::INSTANCE_PARTICLES) {
+ //particles visible? process them
+ if (RSG::storage->particles_is_inactive(idata.base_rid)) {
+ //but if nothing is going on, don't do it.
+ keep = false;
+ } else {
+ cull_data.cull->lock.lock();
+ RSG::storage->particles_request_process(idata.base_rid);
+ cull_data.cull->lock.unlock();
+ RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized(), cull_data.cam_transform.basis.get_axis(1).normalized());
+ //particles visible? request redraw
+ RenderingServerDefault::redraw_request();
+ }
+ }
- if (base_type == RS::INSTANCE_MESH) {
- mesh_visible = true;
- } else if (base_type == RS::INSTANCE_PARTICLES) {
- //particles visible? process them
- if (RSG::storage->particles_is_inactive(idata.base_rid)) {
- //but if nothing is going on, don't do it.
- keep = false;
- } else {
- cull_data.cull->lock.lock();
- RSG::storage->particles_request_process(idata.base_rid);
- cull_data.cull->lock.unlock();
- RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized(), cull_data.cam_transform.basis.get_axis(1).normalized());
- //particles visible? request redraw
- RenderingServerDefault::redraw_request();
+ if (idata.parent_array_index != -1) {
+ float fade = 1.0f;
+ const uint32_t &parent_flags = cull_data.scenario->instance_data[idata.parent_array_index].flags;
+ if (parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN) {
+ const int32_t &parent_idx = cull_data.scenario->instance_data[idata.parent_array_index].visibility_index;
+ fade = cull_data.scenario->instance_visibility[parent_idx].children_fade_alpha;
+ }
+ scene_render->geometry_instance_set_parent_fade_alpha(idata.instance_geometry, fade);
}
- }
- if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) {
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
- uint32_t idx = 0;
+ if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
+ uint32_t idx = 0;
- for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) {
- InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
- instance_pair_buffer[idx++] = light->instance;
- if (idx == MAX_INSTANCE_PAIRS) {
- break;
+ for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) {
+ InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
+ instance_pair_buffer[idx++] = light->instance;
+ if (idx == MAX_INSTANCE_PAIRS) {
+ break;
+ }
}
+
+ scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, instance_pair_buffer, idx);
+ idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_LIGHTING_DIRTY);
}
- scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, instance_pair_buffer, idx);
- idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_LIGHTING_DIRTY);
- }
+ if (idata.flags & InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
+
+ scene_render->geometry_instance_set_softshadow_projector_pairing(geom->geometry_instance, geom->softshadow_count > 0, geom->projector_count > 0);
+ idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY);
+ }
- if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (idata.flags & InstanceData::FLAG_GEOM_REFLECTION_DIRTY)) {
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
- uint32_t idx = 0;
+ if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (idata.flags & InstanceData::FLAG_GEOM_REFLECTION_DIRTY)) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
+ uint32_t idx = 0;
- for (Set<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) {
- InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data);
+ for (Set<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) {
+ InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data);
- instance_pair_buffer[idx++] = reflection_probe->instance;
- if (idx == MAX_INSTANCE_PAIRS) {
- break;
+ instance_pair_buffer[idx++] = reflection_probe->instance;
+ if (idx == MAX_INSTANCE_PAIRS) {
+ break;
+ }
}
- }
- scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, instance_pair_buffer, idx);
- idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_REFLECTION_DIRTY);
- }
+ scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, instance_pair_buffer, idx);
+ idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_REFLECTION_DIRTY);
+ }
- if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) {
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
- uint32_t idx = 0;
+ if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
+ uint32_t idx = 0;
- for (Set<Instance *>::Element *E = geom->decals.front(); E; E = E->next()) {
- InstanceDecalData *decal = static_cast<InstanceDecalData *>(E->get()->base_data);
+ for (Set<Instance *>::Element *E = geom->decals.front(); E; E = E->next()) {
+ InstanceDecalData *decal = static_cast<InstanceDecalData *>(E->get()->base_data);
- instance_pair_buffer[idx++] = decal->instance;
- if (idx == MAX_INSTANCE_PAIRS) {
- break;
+ instance_pair_buffer[idx++] = decal->instance;
+ if (idx == MAX_INSTANCE_PAIRS) {
+ break;
+ }
}
+ scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, instance_pair_buffer, idx);
+ idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY);
}
- scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, instance_pair_buffer, idx);
- idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY);
- }
- if (idata.flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY) {
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
- uint32_t idx = 0;
- for (Set<Instance *>::Element *E = geom->gi_probes.front(); E; E = E->next()) {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(E->get()->base_data);
+ if (idata.flags & InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
+ uint32_t idx = 0;
+ for (Set<Instance *>::Element *E = geom->voxel_gi_instances.front(); E; E = E->next()) {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(E->get()->base_data);
- instance_pair_buffer[idx++] = gi_probe->probe_instance;
- if (idx == MAX_INSTANCE_PAIRS) {
- break;
+ instance_pair_buffer[idx++] = voxel_gi->probe_instance;
+ if (idx == MAX_INSTANCE_PAIRS) {
+ break;
+ }
}
- }
- scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, instance_pair_buffer, idx);
- idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY);
- }
+ scene_render->geometry_instance_pair_voxel_gi_instances(geom->geometry_instance, instance_pair_buffer, idx);
+ idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY);
+ }
- if ((idata.flags & InstanceData::FLAG_LIGHTMAP_CAPTURE) && idata.instance->last_frame_pass != frame_number && !idata.instance->lightmap_target_sh.is_empty() && !idata.instance->lightmap_sh.is_empty()) {
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
- Color *sh = idata.instance->lightmap_sh.ptrw();
- const Color *target_sh = idata.instance->lightmap_target_sh.ptr();
- for (uint32_t j = 0; j < 9; j++) {
- sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed));
+ if ((idata.flags & InstanceData::FLAG_LIGHTMAP_CAPTURE) && idata.instance->last_frame_pass != frame_number && !idata.instance->lightmap_target_sh.is_empty() && !idata.instance->lightmap_sh.is_empty()) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
+ Color *sh = idata.instance->lightmap_sh.ptrw();
+ const Color *target_sh = idata.instance->lightmap_target_sh.ptr();
+ for (uint32_t j = 0; j < 9; j++) {
+ sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed));
+ }
+ scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, sh);
+ idata.instance->last_frame_pass = frame_number;
}
- scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, sh);
- idata.instance->last_frame_pass = frame_number;
- }
- if (keep) {
- cull_result.geometry_instances.push_back(idata.instance_geometry);
+ if (keep) {
+ cull_result.geometry_instances.push_back(idata.instance_geometry);
+ }
}
}
- }
- for (uint32_t j = 0; j < cull_data.cull->shadow_count; j++) {
- for (uint32_t k = 0; k < cull_data.cull->shadows[j].cascade_count; k++) {
- if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->shadows[j].cascades[k].frustum)) {
- InstanceData &idata = cull_data.scenario->instance_data[i];
- uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
+ for (uint32_t j = 0; j < cull_data.cull->shadow_count; j++) {
+ for (uint32_t k = 0; k < cull_data.cull->shadows[j].cascade_count; k++) {
+ if (IN_FRUSTUM(cull_data.cull->shadows[j].cascades[k].frustum) && VIS_CHECK) {
+ uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
- if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS) {
- cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry);
- mesh_visible = true;
+ if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS) {
+ cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry);
+ mesh_visible = true;
+ }
}
}
}
}
+#undef HIDDEN_BY_VISIBILITY_CHECKS
+#undef LAYER_CHECK
+#undef IN_FRUSTUM
+#undef VIS_RANGE_CHECK
+#undef VIS_PARENT_CHECK
+#undef VIS_CHECK
+#undef OCCLUSION_CULLED
+
for (uint32_t j = 0; j < cull_data.cull->sdfgi.region_count; j++) {
if (cull_data.scenario->instance_aabbs[i].in_aabb(cull_data.cull->sdfgi.region_aabb[j])) {
- InstanceData &idata = cull_data.scenario->instance_data[i];
uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
if (base_type == RS::INSTANCE_LIGHT) {
@@ -2544,14 +2862,10 @@ void RendererSceneCull::_frustum_cull(CullData &cull_data, FrustumCullResult &cu
}
}
-void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows) {
- // Note, in stereo rendering:
- // - p_cam_transform will be a transform in the middle of our two eyes
- // - p_cam_projection is a wider frustrum that encompasses both eyes
-
- Instance *render_reflection_probe = instance_owner.getornull(p_reflection_probe); //if null, not rendering to it
+void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_camera_data, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows, RendererScene::RenderInfo *r_render_info) {
+ Instance *render_reflection_probe = instance_owner.get_or_null(p_reflection_probe); //if null, not rendering to it
- Scenario *scenario = scenario_owner.getornull(p_scenario);
+ Scenario *scenario = scenario_owner.get_or_null(p_scenario);
render_pass++;
@@ -2559,19 +2873,44 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
if (p_render_buffers.is_valid()) {
//no rendering code here, this is only to set up what needs to be done, request regions, etc.
- scene_render->sdfgi_update(p_render_buffers, p_environment, p_cam_transform.origin); //update conditions for SDFGI (whether its used or not)
+ scene_render->sdfgi_update(p_render_buffers, p_environment, p_camera_data->main_transform.origin); //update conditions for SDFGI (whether its used or not)
}
- RENDER_TIMESTAMP("Frustum Culling");
+ RENDER_TIMESTAMP("Visibility Dependencies");
- //rasterizer->set_camera(camera->transform, camera_matrix,ortho);
+ if (scenario->instance_visibility.get_bin_count() > 0) {
+ if (!scenario->viewport_visibility_masks.has(p_viewport)) {
+ scenario_add_viewport_visibility_mask(scenario->self, p_viewport);
+ }
- Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform);
+ VisibilityCullData visibility_cull_data;
+ visibility_cull_data.scenario = scenario;
+ visibility_cull_data.viewport_mask = scenario->viewport_visibility_masks[p_viewport];
+ visibility_cull_data.camera_position = p_camera_data->main_transform.origin;
- Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2).normalized());
+ for (int i = scenario->instance_visibility.get_bin_count() - 1; i > 0; i--) { // We skip bin 0
+ visibility_cull_data.cull_offset = scenario->instance_visibility.get_bin_start(i);
+ visibility_cull_data.cull_count = scenario->instance_visibility.get_bin_size(i);
+
+ if (visibility_cull_data.cull_count == 0) {
+ continue;
+ }
+
+ if (visibility_cull_data.cull_count > thread_cull_threshold) {
+ RendererThreadPool::singleton->thread_work_pool.do_work(RendererThreadPool::singleton->thread_work_pool.get_thread_count(), this, &RendererSceneCull::_visibility_cull_threaded, &visibility_cull_data);
+ } else {
+ _visibility_cull(visibility_cull_data, visibility_cull_data.cull_offset, visibility_cull_data.cull_offset + visibility_cull_data.cull_count);
+ }
+ }
+ }
+
+ RENDER_TIMESTAMP("Culling");
+
+ //rasterizer->set_camera(p_camera_data->main_transform, p_camera_data.main_projection, p_camera_data.is_ortogonal);
/* STEP 2 - CULL */
+ Vector<Plane> planes = p_camera_data->main_projection.get_projection_planes(p_camera_data->main_transform);
cull.frustum = Frustum(planes);
Vector<RID> directional_lights;
@@ -2581,8 +2920,8 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
Vector<Instance *> lights_with_shadow;
- for (List<Instance *>::Element *E = scenario->directional_lights.front(); E; E = E->next()) {
- if (!E->get()->visible) {
+ for (Instance *E : scenario->directional_lights) {
+ if (!E->visible) {
continue;
}
@@ -2590,13 +2929,13 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
break;
}
- InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
+ InstanceLightData *light = static_cast<InstanceLightData *>(E->base_data);
//check shadow..
if (light) {
- if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->get()->base) && !(RSG::storage->light_get_type(E->get()->base) == RS::LIGHT_DIRECTIONAL && RSG::storage->light_directional_is_sky_only(E->get()->base))) {
- lights_with_shadow.push_back(E->get());
+ if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->base) && !(RSG::storage->light_get_type(E->base) == RS::LIGHT_DIRECTIONAL && RSG::storage->light_directional_is_sky_only(E->base))) {
+ lights_with_shadow.push_back(E);
}
//add to list
directional_lights.push_back(light->instance);
@@ -2606,7 +2945,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
scene_render->set_directional_shadow_count(lights_with_shadow.size());
for (int i = 0; i < lights_with_shadow.size(); i++) {
- _light_instance_setup_directional_shadow(i, lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect);
+ _light_instance_setup_directional_shadow(i, lights_with_shadow[i], p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_ortogonal, p_camera_data->vaspect);
}
}
@@ -2635,7 +2974,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
}
}
- frustum_cull_result.clear();
+ scene_cull_result.clear();
{
uint64_t cull_from = 0;
@@ -2647,30 +2986,31 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
cull_data.cull = &cull;
cull_data.scenario = scenario;
cull_data.shadow_atlas = p_shadow_atlas;
- cull_data.cam_transform = p_cam_transform;
+ cull_data.cam_transform = p_camera_data->main_transform;
cull_data.visible_layers = p_visible_layers;
cull_data.render_reflection_probe = render_reflection_probe;
cull_data.occlusion_buffer = RendererSceneOcclusionCull::get_singleton()->buffer_get_ptr(p_viewport);
- cull_data.camera_matrix = &p_cam_projection;
+ cull_data.camera_matrix = &p_camera_data->main_projection;
+ cull_data.visibility_viewport_mask = scenario->viewport_visibility_masks.has(p_viewport) ? scenario->viewport_visibility_masks[p_viewport] : 0;
//#define DEBUG_CULL_TIME
#ifdef DEBUG_CULL_TIME
uint64_t time_from = OS::get_singleton()->get_ticks_usec();
#endif
if (cull_to > thread_cull_threshold) {
//multiple threads
- for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) {
- frustum_cull_result_threads[i].clear();
+ for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) {
+ scene_cull_result_threads[i].clear();
}
- RendererThreadPool::singleton->thread_work_pool.do_work(frustum_cull_result_threads.size(), this, &RendererSceneCull::_frustum_cull_threaded, &cull_data);
+ RendererThreadPool::singleton->thread_work_pool.do_work(scene_cull_result_threads.size(), this, &RendererSceneCull::_scene_cull_threaded, &cull_data);
- for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) {
- frustum_cull_result.append_from(frustum_cull_result_threads[i]);
+ for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) {
+ scene_cull_result.append_from(scene_cull_result_threads[i]);
}
} else {
//single threaded
- _frustum_cull(cull_data, frustum_cull_result, cull_from, cull_to);
+ _scene_cull(cull_data, scene_cull_result, cull_from, cull_to);
}
#ifdef DEBUG_CULL_TIME
@@ -2681,9 +3021,9 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
print_line("time taken: " + rtos(time_avg / time_count));
#endif
- if (frustum_cull_result.mesh_instances.size()) {
- for (uint64_t i = 0; i < frustum_cull_result.mesh_instances.size(); i++) {
- RSG::storage->mesh_instance_check_for_update(frustum_cull_result.mesh_instances[i]);
+ if (scene_cull_result.mesh_instances.size()) {
+ for (uint64_t i = 0; i < scene_cull_result.mesh_instances.size(); i++) {
+ RSG::storage->mesh_instance_check_for_update(scene_cull_result.mesh_instances[i]);
}
RSG::storage->update_mesh_instances();
}
@@ -2707,14 +3047,14 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
}
render_shadow_data[max_shadows_used].light = cull.shadows[i].light_instance;
render_shadow_data[max_shadows_used].pass = j;
- render_shadow_data[max_shadows_used].instances.merge_unordered(frustum_cull_result.directional_shadows[i].cascade_geometry_instances[j]);
+ render_shadow_data[max_shadows_used].instances.merge_unordered(scene_cull_result.directional_shadows[i].cascade_geometry_instances[j]);
max_shadows_used++;
}
}
// Positional Shadowss
- for (uint32_t i = 0; i < (uint32_t)frustum_cull_result.lights.size(); i++) {
- Instance *ins = frustum_cull_result.lights[i];
+ for (uint32_t i = 0; i < (uint32_t)scene_cull_result.lights.size(); i++) {
+ Instance *ins = scene_cull_result.lights[i];
if (!p_shadow_atlas.is_valid() || !RSG::storage->light_has_shadow(ins->base)) {
continue;
@@ -2726,12 +3066,12 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
{ //compute coverage
- Transform cam_xf = p_cam_transform;
- float zn = p_cam_projection.get_z_near();
- Plane p(cam_xf.origin + cam_xf.basis.get_axis(2) * -zn, -cam_xf.basis.get_axis(2)); //camera near plane
+ Transform3D cam_xf = p_camera_data->main_transform;
+ float zn = p_camera_data->main_projection.get_z_near();
+ Plane p(-cam_xf.basis.get_axis(2), cam_xf.origin + cam_xf.basis.get_axis(2) * -zn); //camera near plane
// near plane half width and height
- Vector2 vp_half_extents = p_cam_projection.get_viewport_half_extents();
+ Vector2 vp_half_extents = p_camera_data->main_projection.get_viewport_half_extents();
switch (RSG::storage->light_get_type(ins->base)) {
case RS::LIGHT_OMNI: {
@@ -2743,7 +3083,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
ins->transform.origin + cam_xf.basis.get_axis(0) * radius
};
- if (!p_cam_orthogonal) {
+ if (!p_camera_data->is_ortogonal) {
//if using perspetive, map them to near plane
for (int j = 0; j < 2; j++) {
if (p.distance_to(points[j]) < 0) {
@@ -2771,7 +3111,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
base + cam_xf.basis.get_axis(0) * w
};
- if (!p_cam_orthogonal) {
+ if (!p_camera_data->is_ortogonal) {
//if using perspetive, map them to near plane
for (int j = 0; j < 2; j++) {
if (p.distance_to(points[j]) < 0) {
@@ -2802,7 +3142,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
if (redraw && max_shadows_used < MAX_UPDATE_SHADOWS) {
//must redraw!
RENDER_TIMESTAMP(">Rendering Light " + itos(i));
- light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario, p_screen_lod_threshold);
+ light->shadow_dirty = _light_instance_update_shadow(ins, p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_ortogonal, p_camera_data->vaspect, p_shadow_atlas, scenario, p_screen_lod_threshold);
RENDER_TIMESTAMP("<Rendering Light " + itos(i));
} else {
light->shadow_dirty = redraw;
@@ -2818,13 +3158,13 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
if (cull.sdfgi.region_count > 0) {
//update regions
for (uint32_t i = 0; i < cull.sdfgi.region_count; i++) {
- render_sdfgi_data[i].instances.merge_unordered(frustum_cull_result.sdfgi_region_geometry_instances[i]);
+ render_sdfgi_data[i].instances.merge_unordered(scene_cull_result.sdfgi_region_geometry_instances[i]);
render_sdfgi_data[i].region = i;
}
//check if static lights were culled
bool static_lights_culled = false;
for (uint32_t i = 0; i < cull.sdfgi.cascade_light_count; i++) {
- if (frustum_cull_result.sdfgi_cascade_lights[i].size()) {
+ if (scene_cull_result.sdfgi_cascade_lights[i].size()) {
static_lights_culled = true;
break;
}
@@ -2833,7 +3173,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
if (static_lights_culled) {
sdfgi_update_data.static_cascade_count = cull.sdfgi.cascade_light_count;
sdfgi_update_data.static_cascade_indices = cull.sdfgi.cascade_light_index;
- sdfgi_update_data.static_positional_lights = frustum_cull_result.sdfgi_cascade_lights;
+ sdfgi_update_data.static_positional_lights = scene_cull_result.sdfgi_cascade_lights;
sdfgi_update_data.update_static = true;
}
}
@@ -2847,7 +3187,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
//append the directional lights to the lights culled
for (int i = 0; i < directional_lights.size(); i++) {
- frustum_cull_result.light_instances.push_back(directional_lights[i]);
+ scene_cull_result.light_instances.push_back(directional_lights[i]);
}
RID camera_effects;
@@ -2864,7 +3204,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
}
RENDER_TIMESTAMP("Render Scene ");
- scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, frustum_cull_result.geometry_instances, frustum_cull_result.light_instances, frustum_cull_result.reflections, frustum_cull_result.gi_probes, frustum_cull_result.decals, frustum_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data);
+ scene_render->render_scene(p_render_buffers, p_camera_data, scene_cull_result.geometry_instances, scene_cull_result.light_instances, scene_cull_result.reflections, scene_cull_result.voxel_gi_instances, scene_cull_result.decals, scene_cull_result.lightmaps, scene_cull_result.fog_volumes, p_environment, camera_effects, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data, r_render_info);
for (uint32_t i = 0; i < max_shadows_used; i++) {
render_shadow_data[i].instances.clear();
@@ -2875,16 +3215,16 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca
render_sdfgi_data[i].instances.clear();
}
- // virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold,const RenderShadowData *p_render_shadows,int p_render_shadow_count,const RenderSDFGIData *p_render_sdfgi_regions,int p_render_sdfgi_region_count,const RenderSDFGIStaticLightData *p_render_sdfgi_static_lights=nullptr) = 0;
+ // virtual void render_scene(RID p_render_buffers, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold,const RenderShadowData *p_render_shadows,int p_render_shadow_count,const RenderSDFGIData *p_render_sdfgi_regions,int p_render_sdfgi_region_count,const RenderSDFGIStaticLightData *p_render_sdfgi_static_lights=nullptr) = 0;
}
RID RendererSceneCull::_render_get_environment(RID p_camera, RID p_scenario) {
- Camera *camera = camera_owner.getornull(p_camera);
+ Camera *camera = camera_owner.get_or_null(p_camera);
if (camera && scene_render->is_environment(camera->env)) {
return camera->env;
}
- Scenario *scenario = scenario_owner.getornull(p_scenario);
+ Scenario *scenario = scenario_owner.get_or_null(p_scenario);
if (!scenario) {
return RID();
}
@@ -2901,8 +3241,7 @@ RID RendererSceneCull::_render_get_environment(RID p_camera, RID p_scenario) {
void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) {
#ifndef _3D_DISABLED
-
- Scenario *scenario = scenario_owner.getornull(p_scenario);
+ Scenario *scenario = scenario_owner.get_or_null(p_scenario);
RID environment;
if (scenario->environment.is_valid()) {
@@ -2911,7 +3250,11 @@ void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario,
environment = scenario->fallback_environment;
}
RENDER_TIMESTAMP("Render Empty Scene ");
- scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr);
+
+ RendererSceneRender::CameraData camera_data;
+ camera_data.set_camera(Transform3D(), CameraMatrix(), true, false);
+
+ scene_render->render_scene(p_render_buffers, &camera_data, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr);
#endif
}
@@ -2961,10 +3304,10 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
CameraMatrix cm;
cm.set_perspective(90, 1, 0.01, max_distance);
- Transform local_view;
+ Transform3D local_view;
local_view.set_look_at(origin_offset, origin_offset + view_normals[p_step], view_up[p_step]);
- Transform xform = p_instance->transform * local_view;
+ Transform3D xform = p_instance->transform * local_view;
RID shadow_atlas;
@@ -2981,7 +3324,10 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
}
RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step));
- _render_scene(xform, cm, false, false, RID(), environment, RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, lod_threshold, use_shadows);
+ RendererSceneRender::CameraData camera_data;
+ camera_data.set_camera(xform, cm, false, false);
+
+ _render_scene(&camera_data, RID(), environment, RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, lod_threshold, use_shadows);
} else {
//do roughness postprocess step until it believes it's done
@@ -3033,18 +3379,18 @@ void RendererSceneCull::render_probes() {
ref_probe = next;
}
- /* GI PROBES */
+ /* VOXEL GIS */
- SelfList<InstanceGIProbeData> *gi_probe = gi_probe_update_list.first();
+ SelfList<InstanceVoxelGIData> *voxel_gi = voxel_gi_update_list.first();
- if (gi_probe) {
+ if (voxel_gi) {
RENDER_TIMESTAMP("Render GI Probes");
}
- while (gi_probe) {
- SelfList<InstanceGIProbeData> *next = gi_probe->next();
+ while (voxel_gi) {
+ SelfList<InstanceVoxelGIData> *next = voxel_gi->next();
- InstanceGIProbeData *probe = gi_probe->self();
+ InstanceVoxelGIData *probe = voxel_gi->self();
//Instance *instance_probe = probe->owner;
//check if probe must be setup, but don't do if on the lighting thread
@@ -3053,7 +3399,7 @@ void RendererSceneCull::render_probes() {
int cache_count = 0;
{
int light_cache_size = probe->light_cache.size();
- const InstanceGIProbeData::LightCache *caches = probe->light_cache.ptr();
+ const InstanceVoxelGIData::LightCache *caches = probe->light_cache.ptr();
const RID *instance_caches = probe->light_instances.ptr();
int idx = 0; //must count visible lights
@@ -3068,7 +3414,7 @@ void RendererSceneCull::render_probes() {
} else if (idx >= light_cache_size) {
cache_dirty = true;
} else {
- const InstanceGIProbeData::LightCache *cache = &caches[idx];
+ const InstanceVoxelGIData::LightCache *cache = &caches[idx];
if (
instance_caches[idx] != instance_light->instance ||
@@ -3089,8 +3435,7 @@ void RendererSceneCull::render_probes() {
idx++;
}
- for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) {
- Instance *instance = E->get();
+ for (const Instance *instance : probe->owner->scenario->directional_lights) {
InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
if (!instance->visible) {
continue;
@@ -3100,7 +3445,7 @@ void RendererSceneCull::render_probes() {
} else if (idx >= light_cache_size) {
cache_dirty = true;
} else {
- const InstanceGIProbeData::LightCache *cache = &caches[idx];
+ const InstanceVoxelGIData::LightCache *cache = &caches[idx];
if (
instance_caches[idx] != instance_light->instance ||
@@ -3129,14 +3474,14 @@ void RendererSceneCull::render_probes() {
cache_count = idx;
}
- bool update_lights = scene_render->gi_probe_needs_update(probe->probe_instance);
+ bool update_lights = scene_render->voxel_gi_needs_update(probe->probe_instance);
if (cache_dirty) {
probe->light_cache.resize(cache_count);
probe->light_instances.resize(cache_count);
if (cache_count) {
- InstanceGIProbeData::LightCache *caches = probe->light_cache.ptrw();
+ InstanceVoxelGIData::LightCache *caches = probe->light_cache.ptrw();
RID *instance_caches = probe->light_instances.ptrw();
int idx = 0; //must count visible lights
@@ -3147,7 +3492,7 @@ void RendererSceneCull::render_probes() {
continue;
}
- InstanceGIProbeData::LightCache *cache = &caches[idx];
+ InstanceVoxelGIData::LightCache *cache = &caches[idx];
instance_caches[idx] = instance_light->instance;
cache->has_shadow = RSG::storage->light_has_shadow(instance->base);
@@ -3163,14 +3508,13 @@ void RendererSceneCull::render_probes() {
idx++;
}
- for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) {
- Instance *instance = E->get();
+ for (const Instance *instance : probe->owner->scenario->directional_lights) {
InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
if (!instance->visible) {
continue;
}
- InstanceGIProbeData::LightCache *cache = &caches[idx];
+ InstanceVoxelGIData::LightCache *cache = &caches[idx];
instance_caches[idx] = instance_light->instance;
cache->has_shadow = RSG::storage->light_has_shadow(instance->base);
@@ -3192,7 +3536,7 @@ void RendererSceneCull::render_probes() {
update_lights = true;
}
- frustum_cull_result.geometry_instances.clear();
+ scene_cull_result.geometry_instances.clear();
RID instance_pair_buffer[MAX_INSTANCE_PAIRS];
@@ -3203,30 +3547,30 @@ void RendererSceneCull::render_probes() {
}
InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data;
- if (ins->scenario && ins->array_index >= 0 && (ins->scenario->instance_data[ins->array_index].flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY)) {
+ if (ins->scenario && ins->array_index >= 0 && (ins->scenario->instance_data[ins->array_index].flags & InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY)) {
uint32_t idx = 0;
- for (Set<Instance *>::Element *F = geom->gi_probes.front(); F; F = F->next()) {
- InstanceGIProbeData *gi_probe2 = static_cast<InstanceGIProbeData *>(F->get()->base_data);
+ for (Set<Instance *>::Element *F = geom->voxel_gi_instances.front(); F; F = F->next()) {
+ InstanceVoxelGIData *voxel_gi2 = static_cast<InstanceVoxelGIData *>(F->get()->base_data);
- instance_pair_buffer[idx++] = gi_probe2->probe_instance;
+ instance_pair_buffer[idx++] = voxel_gi2->probe_instance;
if (idx == MAX_INSTANCE_PAIRS) {
break;
}
}
- scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, instance_pair_buffer, idx);
+ scene_render->geometry_instance_pair_voxel_gi_instances(geom->geometry_instance, instance_pair_buffer, idx);
- ins->scenario->instance_data[ins->array_index].flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY);
+ ins->scenario->instance_data[ins->array_index].flags &= ~uint32_t(InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY);
}
- frustum_cull_result.geometry_instances.push_back(geom->geometry_instance);
+ scene_cull_result.geometry_instances.push_back(geom->geometry_instance);
}
- scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, frustum_cull_result.geometry_instances);
+ scene_render->voxel_gi_update(probe->probe_instance, update_lights, probe->light_instances, scene_cull_result.geometry_instances);
- gi_probe_update_list.remove(gi_probe);
+ voxel_gi_update_list.remove(voxel_gi);
- gi_probe = next;
+ voxel_gi = next;
}
}
@@ -3237,7 +3581,7 @@ void RendererSceneCull::render_particle_colliders() {
if (hfpc->scenario && hfpc->base_type == RS::INSTANCE_PARTICLES_COLLISION && RSG::storage->particles_collision_is_heightfield(hfpc->base)) {
//update heightfield
instance_cull_result.clear();
- frustum_cull_result.geometry_instances.clear();
+ scene_cull_result.geometry_instances.clear();
struct CullAABB {
PagedArray<Instance *> *result;
@@ -3259,10 +3603,10 @@ void RendererSceneCull::render_particle_colliders() {
continue;
}
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
- frustum_cull_result.geometry_instances.push_back(geom->geometry_instance);
+ scene_cull_result.geometry_instances.push_back(geom->geometry_instance);
}
- scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, frustum_cull_result.geometry_instances);
+ scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, scene_cull_result.geometry_instances);
}
heightfield_particle_colliders_update_list.erase(heightfield_particle_colliders_update_list.front());
}
@@ -3271,26 +3615,26 @@ void RendererSceneCull::render_particle_colliders() {
void RendererSceneCull::_update_instance_shader_parameters_from_material(Map<StringName, Instance::InstanceShaderParameter> &isparams, const Map<StringName, Instance::InstanceShaderParameter> &existing_isparams, RID p_material) {
List<RendererStorage::InstanceShaderParam> plist;
RSG::storage->material_get_instance_shader_parameters(p_material, &plist);
- for (List<RendererStorage::InstanceShaderParam>::Element *E = plist.front(); E; E = E->next()) {
- StringName name = E->get().info.name;
+ for (const RendererStorage::InstanceShaderParam &E : plist) {
+ StringName name = E.info.name;
if (isparams.has(name)) {
- if (isparams[name].info.type != E->get().info.type) {
- WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E->get().info.name + "', but they do it with different data types. Only the first one (in order) will display correctly.");
+ if (isparams[name].info.type != E.info.type) {
+ WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E.info.name + "', but they do it with different data types. Only the first one (in order) will display correctly.");
}
- if (isparams[name].index != E->get().index) {
- WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E->get().info.name + "', but they do it with different indices. Only the first one (in order) will display correctly.");
+ if (isparams[name].index != E.index) {
+ WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E.info.name + "', but they do it with different indices. Only the first one (in order) will display correctly.");
}
continue; //first one found always has priority
}
Instance::InstanceShaderParameter isp;
- isp.index = E->get().index;
- isp.info = E->get().info;
- isp.default_value = E->get().default_value;
+ isp.index = E.index;
+ isp.info = E.info;
+ isp.default_value = E.default_value;
if (existing_isparams.has(name)) {
isp.value = existing_isparams[name].value;
} else {
- isp.value = E->get().default_value;
+ isp.value = E.default_value;
}
isparams[name] = isp;
}
@@ -3402,25 +3746,6 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
RSG::storage->base_update_dependency(mesh, &p_instance->dependency_tracker);
}
- } else if (p_instance->base_type == RS::INSTANCE_IMMEDIATE) {
- RID mat = RSG::storage->immediate_get_material(p_instance->base);
-
- if (!(!mat.is_valid() || RSG::storage->material_casts_shadows(mat))) {
- can_cast_shadows = false;
- }
-
- if (mat.is_valid() && RSG::storage->material_is_animated(mat)) {
- is_animated = true;
- }
-
- if (mat.is_valid()) {
- _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat);
- }
-
- if (mat.is_valid()) {
- RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker);
- }
-
} else if (p_instance->base_type == RS::INSTANCE_PARTICLES) {
bool cast_shadows = false;
@@ -3479,9 +3804,9 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
p_instance->instance_allocated_shader_parameters_offset = RSG::storage->global_variables_instance_allocate(p_instance->self);
scene_render->geometry_instance_set_instance_shader_parameters_offset(geom->geometry_instance, p_instance->instance_allocated_shader_parameters_offset);
- for (Map<StringName, Instance::InstanceShaderParameter>::Element *E = p_instance->instance_shader_parameters.front(); E; E = E->next()) {
- if (E->get().value.get_type() != Variant::NIL) {
- RSG::storage->global_variables_instance_update(p_instance->self, E->get().index, E->get().value);
+ for (const KeyValue<StringName, Instance::InstanceShaderParameter> &E : p_instance->instance_shader_parameters) {
+ if (E.value.value.get_type() != Variant::NIL) {
+ RSG::storage->global_variables_instance_update(p_instance->self, E.value.index, E.value.value);
}
}
} else {
@@ -3533,30 +3858,31 @@ void RendererSceneCull::update() {
}
bool RendererSceneCull::free(RID p_rid) {
+ if (p_rid.is_null()) {
+ return true;
+ }
+
if (scene_render->free(p_rid)) {
return true;
}
if (camera_owner.owns(p_rid)) {
- Camera *camera = camera_owner.getornull(p_rid);
-
camera_owner.free(p_rid);
- memdelete(camera);
} else if (scenario_owner.owns(p_rid)) {
- Scenario *scenario = scenario_owner.getornull(p_rid);
+ Scenario *scenario = scenario_owner.get_or_null(p_rid);
while (scenario->instances.first()) {
instance_set_scenario(scenario->instances.first()->self()->self, RID());
}
scenario->instance_aabbs.reset();
scenario->instance_data.reset();
+ scenario->instance_visibility.reset();
scene_render->free(scenario->reflection_probe_shadow_atlas);
scene_render->free(scenario->reflection_atlas);
scenario_owner.free(p_rid);
RendererSceneOcclusionCull::get_singleton()->remove_scenario(p_rid);
- memdelete(scenario);
} else if (RendererSceneOcclusionCull::get_singleton()->is_occluder(p_rid)) {
RendererSceneOcclusionCull::get_singleton()->free_occluder(p_rid);
@@ -3565,7 +3891,7 @@ bool RendererSceneCull::free(RID p_rid) {
update_dirty_instances();
- Instance *instance = instance_owner.getornull(p_rid);
+ Instance *instance = instance_owner.get_or_null(p_rid);
instance_geometry_set_lightmap(p_rid, RID(), Rect2(), 0);
instance_set_scenario(p_rid, RID());
@@ -3580,7 +3906,6 @@ bool RendererSceneCull::free(RID p_rid) {
update_dirty_instances(); //in case something changed this
instance_owner.free(p_rid);
- memdelete(instance);
} else {
return false;
}
@@ -3592,6 +3917,28 @@ TypedArray<Image> RendererSceneCull::bake_render_uv2(RID p_base, const Vector<RI
return scene_render->bake_render_uv2(p_base, p_material_overrides, p_image_size);
}
+void RendererSceneCull::update_visibility_notifiers() {
+ SelfList<InstanceVisibilityNotifierData> *E = visible_notifier_list.first();
+ while (E) {
+ SelfList<InstanceVisibilityNotifierData> *N = E->next();
+
+ InstanceVisibilityNotifierData *visibility_notifier = E->self();
+ if (visibility_notifier->just_visible) {
+ visibility_notifier->just_visible = false;
+
+ RSG::storage->visibility_notifier_call(visibility_notifier->base, true, RSG::threaded);
+ } else {
+ if (visibility_notifier->visible_in_frame != RSG::rasterizer->get_frame_number()) {
+ visible_notifier_list.remove(E);
+
+ RSG::storage->visibility_notifier_call(visibility_notifier->base, false, RSG::threaded);
+ }
+ }
+
+ E = N;
+ }
+}
+
/*******************************/
/* Passthrough to Scene Render */
/*******************************/
@@ -3619,10 +3966,10 @@ RendererSceneCull::RendererSceneCull() {
render_sdfgi_data[i].instances.set_page_pool(&geometry_instance_cull_page_pool);
}
- frustum_cull_result.init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool);
- frustum_cull_result_threads.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
- for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) {
- frustum_cull_result_threads[i].init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool);
+ scene_cull_result.init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool);
+ scene_cull_result_threads.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
+ for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) {
+ scene_cull_result_threads[i].init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool);
}
indexer_update_iterations = GLOBAL_GET("rendering/limits/spatial_indexer/update_iterations_per_frame");
@@ -3643,11 +3990,11 @@ RendererSceneCull::~RendererSceneCull() {
render_sdfgi_data[i].instances.reset();
}
- frustum_cull_result.reset();
- for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) {
- frustum_cull_result_threads[i].reset();
+ scene_cull_result.reset();
+ for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) {
+ scene_cull_result_threads[i].reset();
}
- frustum_cull_result_threads.clear();
+ scene_cull_result_threads.clear();
if (dummy_occlusion_culling) {
memdelete(dummy_occlusion_culling);
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index a61b04afc8..e51a1fc02e 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -31,6 +31,7 @@
#ifndef RENDERING_SERVER_SCENE_CULL_H
#define RENDERING_SERVER_SCENE_CULL_H
+#include "core/templates/bin_sorted_array.h"
#include "core/templates/pass_func.h"
#include "servers/rendering/renderer_compositor.h"
@@ -82,7 +83,7 @@ public:
RID env;
RID effects;
- Transform transform;
+ Transform3D transform;
Camera() {
visible_layers = 0xFFFFFFFF;
@@ -96,7 +97,7 @@ public:
}
};
- mutable RID_PtrOwner<Camera, true> camera_owner;
+ mutable RID_Owner<Camera, true> camera_owner;
virtual RID camera_allocate();
virtual void camera_initialize(RID p_rid);
@@ -104,7 +105,7 @@ public:
virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far);
virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far);
virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far);
- virtual void camera_set_transform(RID p_camera, const Transform &p_transform);
+ virtual void camera_set_transform(RID p_camera, const Transform3D &p_transform);
virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers);
virtual void camera_set_environment(RID p_camera, RID p_env);
virtual void camera_set_camera_effects(RID p_camera, RID p_fx);
@@ -117,6 +118,8 @@ public:
virtual void occluder_initialize(RID p_occluder);
virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices);
+ /* VISIBILITY NOTIFIER API */
+
RendererSceneOcclusionCull *dummy_occlusion_culling;
/* SCENARIO API */
@@ -242,6 +245,8 @@ public:
}
};
+ struct InstanceVisibilityNotifierData;
+
struct InstanceData {
// Store instance pointer as well as common instance processing information,
// to make processing more cache friendly.
@@ -253,12 +258,18 @@ public:
FLAG_GEOM_LIGHTING_DIRTY = (1 << 11),
FLAG_GEOM_REFLECTION_DIRTY = (1 << 12),
FLAG_GEOM_DECAL_DIRTY = (1 << 13),
- FLAG_GEOM_GI_PROBE_DIRTY = (1 << 14),
+ FLAG_GEOM_VOXEL_GI_DIRTY = (1 << 14),
FLAG_LIGHTMAP_CAPTURE = (1 << 15),
FLAG_USES_BAKED_LIGHT = (1 << 16),
FLAG_USES_MESH_INSTANCE = (1 << 17),
FLAG_REFLECTION_PROBE_DIRTY = (1 << 18),
FLAG_IGNORE_OCCLUSION_CULLING = (1 << 19),
+ FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK = (3 << 20), // 2 bits, overlaps with the other vis. dependency flags
+ FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE = (1 << 20),
+ FLAG_VISIBILITY_DEPENDENCY_HIDDEN = (1 << 21),
+ FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN = (1 << 22),
+ FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY = (1 << 23),
+ FLAG_IGNORE_ALL_CULLING = (1 << 24),
};
uint32_t flags = 0;
@@ -267,12 +278,38 @@ public:
union {
uint64_t instance_data_rid;
RendererSceneRender::GeometryInstance *instance_geometry;
+ InstanceVisibilityNotifierData *visibility_notifier;
};
Instance *instance = nullptr;
+ int32_t parent_array_index = -1;
+ int32_t visibility_index = -1;
+ };
+
+ struct InstanceVisibilityData {
+ uint64_t viewport_state = 0;
+ int32_t array_index = -1;
+ RS::VisibilityRangeFadeMode fade_mode = RS::VISIBILITY_RANGE_FADE_DISABLED;
+ Vector3 position;
+ Instance *instance = nullptr;
+ float range_begin = 0.0f;
+ float range_end = 0.0f;
+ float range_begin_margin = 0.0f;
+ float range_end_margin = 0.0f;
+ float children_fade_alpha = 1.0f;
+ };
+
+ class VisibilityArray : public BinSortedArray<InstanceVisibilityData> {
+ _FORCE_INLINE_ virtual void _update_idx(InstanceVisibilityData &r_element, uint64_t p_idx) {
+ r_element.instance->visibility_index = p_idx;
+ if (r_element.instance->scenario && r_element.instance->array_index != -1) {
+ r_element.instance->scenario->instance_data[r_element.instance->array_index].visibility_index = p_idx;
+ }
+ }
};
PagedArrayPool<InstanceBounds> instance_aabb_page_pool;
PagedArrayPool<InstanceData> instance_data_page_pool;
+ PagedArrayPool<InstanceVisibilityData> instance_visibility_data_page_pool;
struct Scenario {
enum IndexerType {
@@ -283,7 +320,6 @@ public:
DynamicBVH indexers[INDEXER_MAX];
- RS::ScenarioDebugMode debug;
RID self;
List<Instance *> directional_lights;
@@ -292,6 +328,8 @@ public:
RID camera_effects;
RID reflection_probe_shadow_atlas;
RID reflection_atlas;
+ uint64_t used_viewport_visibility_bits;
+ Map<RID, uint64_t> viewport_visibility_masks;
SelfList<Instance>::List instances;
@@ -299,17 +337,18 @@ public:
PagedArray<InstanceBounds> instance_aabbs;
PagedArray<InstanceData> instance_data;
+ VisibilityArray instance_visibility;
Scenario() {
indexers[INDEXER_GEOMETRY].set_index(INDEXER_GEOMETRY);
indexers[INDEXER_VOLUMES].set_index(INDEXER_VOLUMES);
- debug = RS::SCENARIO_DEBUG_DISABLED;
+ used_viewport_visibility_bits = 0;
}
};
int indexer_update_iterations = 0;
- mutable RID_PtrOwner<Scenario, true> scenario_owner;
+ mutable RID_Owner<Scenario, true> scenario_owner;
static void _instance_pair(Instance *p_A, Instance *p_B);
static void _instance_unpair(Instance *p_A, Instance *p_B);
@@ -319,13 +358,14 @@ public:
virtual RID scenario_allocate();
virtual void scenario_initialize(RID p_rid);
- virtual void scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode);
virtual void scenario_set_environment(RID p_scenario, RID p_environment);
virtual void scenario_set_camera_effects(RID p_scenario, RID p_fx);
virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment);
virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count);
virtual bool is_scenario(RID p_scenario) const;
virtual RID scenario_get_environment(RID p_scenario);
+ virtual void scenario_add_viewport_visibility_mask(RID p_scenario, RID p_viewport);
+ virtual void scenario_remove_viewport_visibility_mask(RID p_scenario, RID p_viewport);
/* INSTANCING API */
@@ -353,11 +393,12 @@ public:
RID mesh_instance; //only used for meshes and when skeleton/blendshapes exist
- Transform transform;
+ Transform3D transform;
float lod_bias;
bool ignore_occlusion_culling;
+ bool ignore_all_culling;
Vector<RID> materials;
@@ -398,8 +439,18 @@ public:
RID self;
//scenario stuff
DynamicBVH::ID indexer_id;
- int32_t array_index;
- Scenario *scenario;
+ int32_t array_index = -1;
+ int32_t visibility_index = -1;
+ float visibility_range_begin = 0.0f;
+ float visibility_range_end = 0.0f;
+ float visibility_range_begin_margin = 0.0f;
+ float visibility_range_end_margin = 0.0f;
+ RS::VisibilityRangeFadeMode visibility_range_fade_mode = RS::VISIBILITY_RANGE_FADE_DISABLED;
+ Instance *visibility_parent = nullptr;
+ Set<Instance *> visibility_dependencies;
+ uint32_t visibility_dependencies_depth = 0;
+ float transparency = 0.0f;
+ Scenario *scenario = nullptr;
SelfList<Instance> scenario_item;
//aabb stuff
@@ -412,12 +463,6 @@ public:
float extra_margin;
ObjectID object_id;
- float lod_begin;
- float lod_end;
- float lod_begin_hysteresis;
- float lod_end_hysteresis;
- RID lod_instance;
-
Vector<Color> lightmap_target_sh; //target is used for incrementally changing the SH over time, this avoids pops in some corner cases and when going interior <-> exterior
uint64_t last_frame_pass;
@@ -454,6 +499,14 @@ public:
case RendererStorage::DEPENDENCY_CHANGED_SKELETON_BONES: {
//ignored
} break;
+ case RendererStorage::DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR: {
+ //requires repairing
+ if (instance->indexer_id.is_valid()) {
+ singleton->_unpair_instance(instance);
+ singleton->_instance_queue_update(instance, true, true);
+ }
+
+ } break;
}
}
@@ -485,6 +538,7 @@ public:
lightmap_cull_index = 0;
lod_bias = 1.0;
ignore_occlusion_culling = false;
+ ignore_all_culling = false;
scenario = nullptr;
@@ -495,10 +549,10 @@ public:
visible = true;
- lod_begin = 0;
- lod_end = 0;
- lod_begin_hysteresis = 0;
- lod_end_hysteresis = 0;
+ visibility_range_begin = 0;
+ visibility_range_end = 0;
+ visibility_range_begin_margin = 0;
+ visibility_range_end_margin = 0;
last_frame_pass = 0;
version = 1;
@@ -532,10 +586,12 @@ public:
Set<Instance *> lights;
bool can_cast_shadows;
bool material_is_animated;
+ uint32_t projector_count = 0;
+ uint32_t softshadow_count = 0;
Set<Instance *> decals;
Set<Instance *> reflection_probes;
- Set<Instance *> gi_probes;
+ Set<Instance *> voxel_gi_instances;
Set<Instance *> lightmap_captures;
InstanceGeometryData() {
@@ -576,12 +632,31 @@ public:
RID instance;
};
+ struct InstanceFogVolumeData : public InstanceBaseData {
+ RID instance;
+ bool is_global;
+ };
+
+ struct InstanceVisibilityNotifierData : public InstanceBaseData {
+ bool just_visible = false;
+ uint64_t visible_in_frame = 0;
+ RID base;
+ SelfList<InstanceVisibilityNotifierData> list_element;
+ InstanceVisibilityNotifierData() :
+ list_element(this) {}
+ };
+
+ SpinLock visible_notifier_list_lock;
+ SelfList<InstanceVisibilityNotifierData>::List visible_notifier_list;
+
struct InstanceLightData : public InstanceBaseData {
RID instance;
uint64_t last_version;
List<Instance *>::Element *D; // directional light in scenario
bool shadow_dirty;
+ bool uses_projector = false;
+ bool uses_softshadow = false;
Set<Instance *> geometries;
@@ -599,7 +674,7 @@ public:
}
};
- struct InstanceGIProbeData : public InstanceBaseData {
+ struct InstanceVoxelGIData : public InstanceBaseData {
Instance *owner;
Set<Instance *> geometries;
@@ -609,7 +684,7 @@ public:
struct LightCache {
RS::LightType type;
- Transform transform;
+ Transform3D transform;
Color color;
float energy;
float bake_energy;
@@ -629,16 +704,16 @@ public:
bool invalid;
uint32_t base_version;
- SelfList<InstanceGIProbeData> update_element;
+ SelfList<InstanceVoxelGIData> update_element;
- InstanceGIProbeData() :
+ InstanceVoxelGIData() :
update_element(this) {
invalid = true;
base_version = 0;
}
};
- SelfList<InstanceGIProbeData>::List gi_probe_update_list;
+ SelfList<InstanceVoxelGIData>::List voxel_gi_update_list;
struct InstanceLightmapData : public InstanceBaseData {
RID instance;
@@ -717,15 +792,16 @@ public:
PagedArray<Instance *> instance_cull_result;
PagedArray<Instance *> instance_shadow_cull_result;
- struct FrustumCullResult {
+ struct InstanceCullResult {
PagedArray<RendererSceneRender::GeometryInstance *> geometry_instances;
PagedArray<Instance *> lights;
PagedArray<RID> light_instances;
PagedArray<RID> lightmaps;
PagedArray<RID> reflections;
PagedArray<RID> decals;
- PagedArray<RID> gi_probes;
+ PagedArray<RID> voxel_gi_instances;
PagedArray<RID> mesh_instances;
+ PagedArray<RID> fog_volumes;
struct DirectionalShadow {
PagedArray<RendererSceneRender::GeometryInstance *> cascade_geometry_instances[RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES];
@@ -741,8 +817,9 @@ public:
lightmaps.clear();
reflections.clear();
decals.clear();
- gi_probes.clear();
+ voxel_gi_instances.clear();
mesh_instances.clear();
+ fog_volumes.clear();
for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) {
for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) {
directional_shadows[i].cascade_geometry_instances[j].clear();
@@ -765,8 +842,9 @@ public:
lightmaps.reset();
reflections.reset();
decals.reset();
- gi_probes.reset();
+ voxel_gi_instances.reset();
mesh_instances.reset();
+ fog_volumes.reset();
for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) {
for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) {
directional_shadows[i].cascade_geometry_instances[j].reset();
@@ -782,15 +860,16 @@ public:
}
}
- void append_from(FrustumCullResult &p_cull_result) {
+ void append_from(InstanceCullResult &p_cull_result) {
geometry_instances.merge_unordered(p_cull_result.geometry_instances);
lights.merge_unordered(p_cull_result.lights);
light_instances.merge_unordered(p_cull_result.light_instances);
lightmaps.merge_unordered(p_cull_result.lightmaps);
reflections.merge_unordered(p_cull_result.reflections);
decals.merge_unordered(p_cull_result.decals);
- gi_probes.merge_unordered(p_cull_result.gi_probes);
+ voxel_gi_instances.merge_unordered(p_cull_result.voxel_gi_instances);
mesh_instances.merge_unordered(p_cull_result.mesh_instances);
+ fog_volumes.merge_unordered(p_cull_result.fog_volumes);
for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) {
for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) {
@@ -814,8 +893,9 @@ public:
lightmaps.set_page_pool(p_rid_pool);
reflections.set_page_pool(p_rid_pool);
decals.set_page_pool(p_rid_pool);
- gi_probes.set_page_pool(p_rid_pool);
+ voxel_gi_instances.set_page_pool(p_rid_pool);
mesh_instances.set_page_pool(p_rid_pool);
+ fog_volumes.set_page_pool(p_rid_pool);
for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) {
for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) {
directional_shadows[i].cascade_geometry_instances[j].set_page_pool(p_geometry_instance_pool);
@@ -832,8 +912,8 @@ public:
}
};
- FrustumCullResult frustum_cull_result;
- LocalVector<FrustumCullResult> frustum_cull_result_threads;
+ InstanceCullResult scene_cull_result;
+ LocalVector<InstanceCullResult> scene_cull_result_threads;
RendererSceneRender::RenderShadowData render_shadow_data[MAX_UPDATE_SHADOWS];
uint32_t max_shadows_used = 0;
@@ -843,9 +923,9 @@ public:
uint32_t thread_cull_threshold = 200;
- RID_PtrOwner<Instance, true> instance_owner;
+ RID_Owner<Instance, true> instance_owner;
- uint32_t geometry_instance_pair_mask; // used in traditional forward, unnecesary on clustered
+ uint32_t geometry_instance_pair_mask; // used in traditional forward, unnecessary on clustered
virtual RID instance_allocate();
virtual void instance_initialize(RID p_rid);
@@ -853,19 +933,26 @@ public:
virtual void instance_set_base(RID p_instance, RID p_base);
virtual void instance_set_scenario(RID p_instance, RID p_scenario);
virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask);
- virtual void instance_set_transform(RID p_instance, const Transform &p_transform);
+ virtual void instance_set_transform(RID p_instance, const Transform3D &p_transform);
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id);
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight);
virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material);
virtual void instance_set_visible(RID p_instance, bool p_visible);
+ virtual void instance_geometry_set_transparency(RID p_instance, float p_transparency);
virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb);
virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton);
- virtual void instance_set_exterior(RID p_instance, bool p_enabled);
virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin);
+ virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance);
+
+ virtual void instance_set_ignore_culling(RID p_instance, bool p_enabled);
+
+ bool _update_instance_visibility_depth(Instance *p_instance);
+ void _update_instance_visibility_dependencies(Instance *p_instance);
+
// don't use these in a game!
virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const;
virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const;
@@ -875,8 +962,8 @@ public:
virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting);
virtual void instance_geometry_set_material_override(RID p_instance, RID p_material);
- virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin);
- virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance);
+ virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin, RS::VisibilityRangeFadeMode p_fade_mode);
+
virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index);
virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias);
@@ -893,9 +980,9 @@ public:
_FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance);
void _unpair_instance(Instance *p_instance);
- void _light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect);
+ void _light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform3D p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect);
- _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_scren_lod_threshold);
+ _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform3D p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_scren_lod_threshold);
RID _render_get_environment(RID p_camera, RID p_scenario);
@@ -906,7 +993,7 @@ public:
Frustum frustum;
CameraMatrix projection;
- Transform transform;
+ Transform3D transform;
real_t zfar;
real_t split;
real_t shadow_texel_size;
@@ -937,26 +1024,40 @@ public:
Frustum frustum;
} cull;
+ struct VisibilityCullData {
+ uint64_t viewport_mask;
+ Scenario *scenario;
+ Vector3 camera_position;
+ uint32_t cull_offset;
+ uint32_t cull_count;
+ };
+
+ void _visibility_cull_threaded(uint32_t p_thread, VisibilityCullData *cull_data);
+ void _visibility_cull(const VisibilityCullData &cull_data, uint64_t p_from, uint64_t p_to);
+ template <bool p_fade_check>
+ _FORCE_INLINE_ int _visibility_range_check(InstanceVisibilityData &r_vis_data, const Vector3 &p_camera_pos, uint64_t p_viewport_mask);
+
struct CullData {
Cull *cull;
Scenario *scenario;
RID shadow_atlas;
- Transform cam_transform;
+ Transform3D cam_transform;
uint32_t visible_layers;
Instance *render_reflection_probe;
const RendererSceneOcclusionCull::HZBuffer *occlusion_buffer;
const CameraMatrix *camera_matrix;
+ uint64_t visibility_viewport_mask;
};
- void _frustum_cull_threaded(uint32_t p_thread, CullData *cull_data);
- void _frustum_cull(CullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to);
+ void _scene_cull_threaded(uint32_t p_thread, CullData *cull_data);
+ void _scene_cull(CullData &cull_data, InstanceCullResult &cull_result, uint64_t p_from, uint64_t p_to);
+ _FORCE_INLINE_ bool _visibility_parent_check(const CullData &p_cull_data, const InstanceData &p_instance_data);
bool _render_reflection_probe_step(Instance *p_instance, int p_step);
- void _render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows = true);
+ void _render_scene(const RendererSceneRender::CameraData *p_camera_data, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows = true, RenderInfo *r_render_info = nullptr);
void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas);
- void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas);
- void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas);
+ void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RendererScene::RenderInfo *r_render_info = nullptr);
void update_dirty_instances();
void render_particle_colliders();
@@ -975,7 +1076,7 @@ public:
#define PASSBASE scene_render
PASS2(directional_shadow_atlas_set_size, int, bool)
- PASS1(gi_probe_set_quality, RS::GIProbeQuality)
+ PASS1(voxel_gi_set_quality, RS::VoxelGIQuality)
/* SKY API */
@@ -999,7 +1100,7 @@ public:
PASS2(environment_set_bg_color, RID, const Color &)
PASS2(environment_set_bg_energy, RID, float)
PASS2(environment_set_canvas_max_layer, RID, int)
- PASS7(environment_set_ambient_light, RID, const Color &, RS::EnvironmentAmbientSource, float, float, RS::EnvironmentReflectionSource, const Color &)
+ PASS6(environment_set_ambient_light, RID, const Color &, RS::EnvironmentAmbientSource, float, float, RS::EnvironmentReflectionSource)
PASS6(environment_set_ssr, RID, bool, int, float, float, float)
PASS1(environment_set_ssr_roughness_quality, RS::EnvironmentSSRRoughnessQuality)
@@ -1016,7 +1117,7 @@ public:
PASS7(environment_set_adjustment, RID, bool, float, float, float, bool, RID)
PASS9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float)
- PASS10(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, bool, float)
+ PASS13(environment_set_volumetric_fog, RID, bool, float, const Color &, const Color &, float, float, float, float, float, bool, float, float)
PASS2(environment_set_volumetric_fog_volume_size, int, int)
PASS1(environment_set_volumetric_fog_filter_active, bool)
@@ -1054,7 +1155,7 @@ public:
/* Render Buffers */
PASS0R(RID, render_buffers_create)
- PASS7(render_buffers_configure, RID, RID, int, int, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool)
+ PASS12(render_buffers_configure, RID, RID, int, int, int, int, float, float, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool, uint32_t)
PASS1(gi_set_use_half_resolution, bool)
/* Shadow Atlas */
@@ -1064,14 +1165,19 @@ public:
PASS1(set_debug_draw_mode, RS::ViewportDebugDraw)
+ PASS1(decals_set_filter, RS::DecalFilter)
+ PASS1(light_projectors_set_filter, RS::LightProjectorFilter)
+
virtual void update();
bool free(RID p_rid);
void set_scene_render(RendererSceneRender *p_scene_render);
+ virtual void update_visibility_notifiers();
+
RendererSceneCull();
virtual ~RendererSceneCull();
};
-#endif // VISUALSERVERSCENE_H
+#endif // RENDERING_SERVER_SCENE_CULL_H
diff --git a/servers/rendering/renderer_scene_occlusion_cull.cpp b/servers/rendering/renderer_scene_occlusion_cull.cpp
index c491ccbe7a..1b8aea36d7 100644
--- a/servers/rendering/renderer_scene_occlusion_cull.cpp
+++ b/servers/rendering/renderer_scene_occlusion_cull.cpp
@@ -172,7 +172,7 @@ RID RendererSceneOcclusionCull::HZBuffer::get_debug_texture() {
}
if (debug_image.is_null()) {
- debug_image.instance();
+ debug_image.instantiate();
}
unsigned char *ptrw = debug_data.ptrw();
@@ -185,7 +185,7 @@ RID RendererSceneOcclusionCull::HZBuffer::get_debug_texture() {
if (debug_texture.is_null()) {
debug_texture = RS::get_singleton()->texture_2d_create(debug_image);
} else {
- RenderingServer::get_singleton()->texture_2d_update_immediate(debug_texture, debug_image);
+ RenderingServer::get_singleton()->texture_2d_update(debug_texture, debug_image);
}
return debug_texture;
diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h
index 390bbaa64b..4e4b1b94db 100644
--- a/servers/rendering/renderer_scene_occlusion_cull.h
+++ b/servers/rendering/renderer_scene_occlusion_cull.h
@@ -60,7 +60,7 @@ public:
void update_mips();
- _FORCE_INLINE_ bool is_occluded(const float p_bounds[6], const Vector3 &p_cam_position, const Transform &p_cam_inv_transform, const CameraMatrix &p_cam_projection, float p_near) const {
+ _FORCE_INLINE_ bool is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const CameraMatrix &p_cam_projection, real_t p_near) const {
if (is_empty()) {
return false;
}
@@ -76,26 +76,28 @@ public:
return false;
}
- float min_depth;
- if (p_cam_projection.is_orthogonal()) {
- min_depth = (-closest_point_view.z) - p_near;
- } else {
- float r = -p_near / closest_point_view.z;
- Vector3 closest_point_proj = Vector3(closest_point_view.x * r, closest_point_view.y * r, -p_near);
- min_depth = closest_point_proj.distance_to(closest_point_view);
- }
+ float min_depth = -closest_point_view.z * 0.95f;
Vector2 rect_min = Vector2(FLT_MAX, FLT_MAX);
Vector2 rect_max = Vector2(FLT_MIN, FLT_MIN);
for (int j = 0; j < 8; j++) {
- Vector3 c = RendererSceneOcclusionCull::HZBuffer::corners[j];
+ const Vector3 &c = RendererSceneOcclusionCull::HZBuffer::corners[j];
Vector3 nc = Vector3(1, 1, 1) - c;
Vector3 corner = Vector3(p_bounds[0] * c.x + p_bounds[3] * nc.x, p_bounds[1] * c.y + p_bounds[4] * nc.y, p_bounds[2] * c.z + p_bounds[5] * nc.z);
Vector3 view = p_cam_inv_transform.xform(corner);
- Vector3 projected = p_cam_projection.xform(view);
- Vector2 normalized = Vector2(projected.x * 0.5f + 0.5f, projected.y * 0.5f + 0.5f);
+ Plane vp = Plane(view, 1.0);
+ Plane projected = p_cam_projection.xform4(vp);
+
+ float w = projected.d;
+ if (w < 1.0) {
+ rect_min = Vector2(0.0f, 0.0f);
+ rect_max = Vector2(1.0f, 1.0f);
+ break;
+ }
+
+ Vector2 normalized = Vector2(projected.normal.x / w * 0.5f + 0.5f, projected.normal.y / w * 0.5f + 0.5f);
rect_min = rect_min.min(normalized);
rect_max = rect_max.max(normalized);
}
@@ -171,7 +173,7 @@ public:
virtual void add_scenario(RID p_scenario) {}
virtual void remove_scenario(RID p_scenario) {}
- virtual void scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform &p_xform, bool p_enabled) { _print_warining(); }
+ virtual void scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform3D &p_xform, bool p_enabled) { _print_warining(); }
virtual void scenario_remove_instance(RID p_scenario, RID p_instance) { _print_warining(); }
virtual void add_buffer(RID p_buffer) { _print_warining(); }
@@ -181,7 +183,7 @@ public:
}
virtual void buffer_set_scenario(RID p_buffer, RID p_scenario) { _print_warining(); }
virtual void buffer_set_size(RID p_buffer, const Vector2i &p_size) { _print_warining(); }
- virtual void buffer_update(RID p_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) {}
+ virtual void buffer_update(RID p_buffer, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) {}
virtual RID buffer_get_debug_texture(RID p_buffer) {
_print_warining();
return RID();
diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp
index f27bdc6798..38d1218dee 100644
--- a/servers/rendering/renderer_scene_render.cpp
+++ b/servers/rendering/renderer_scene_render.cpp
@@ -29,3 +29,153 @@
/*************************************************************************/
#include "renderer_scene_render.h"
+
+void RendererSceneRender::CameraData::set_camera(const Transform3D p_transform, const CameraMatrix p_projection, bool p_is_ortogonal, bool p_vaspect) {
+ view_count = 1;
+ is_ortogonal = p_is_ortogonal;
+ vaspect = p_vaspect;
+
+ main_transform = p_transform;
+ main_projection = p_projection;
+
+ view_offset[0] = Transform3D();
+ view_projection[0] = p_projection;
+}
+
+void RendererSceneRender::CameraData::set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const CameraMatrix *p_projections, bool p_is_ortogonal, bool p_vaspect) {
+ ERR_FAIL_COND_MSG(p_view_count != 2, "Incorrect view count for stereoscopic view");
+
+ view_count = p_view_count;
+ is_ortogonal = p_is_ortogonal;
+ vaspect = p_vaspect;
+ Vector<Plane> planes[2];
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Figure out our center transform
+
+ // 1. obtain our planes
+ for (uint32_t v = 0; v < view_count; v++) {
+ planes[v] = p_projections[v].get_projection_planes(p_transforms[v]);
+ }
+
+ // 2. average and normalize plane normals to obtain z vector, cross them to obtain y vector, and from there the x vector for combined camera basis.
+ Vector3 n0 = planes[0][CameraMatrix::PLANE_LEFT].normal;
+ Vector3 n1 = planes[1][CameraMatrix::PLANE_RIGHT].normal;
+ Vector3 z = (n0 + n1).normalized();
+ Vector3 y = n0.cross(n1).normalized();
+ Vector3 x = y.cross(z).normalized();
+ y = z.cross(x).normalized();
+ main_transform.basis.set(x, y, z);
+
+ // 3. create a horizon plane with one of the eyes and the up vector as normal.
+ Plane horizon(y, p_transforms[0].origin);
+
+ // 4. Intersect horizon, left and right to obtain the combined camera origin.
+ ERR_FAIL_COND_MSG(
+ !horizon.intersect_3(planes[0][CameraMatrix::PLANE_LEFT], planes[1][CameraMatrix::PLANE_RIGHT], &main_transform.origin), "Can't determine camera origin");
+
+ // handy to have the inverse of the transform we just build
+ Transform3D main_transform_inv = main_transform.inverse();
+
+ // 5. figure out far plane, this could use some improvement, we may have our far plane too close like this, not sure if this matters
+ Vector3 far_center = (planes[0][CameraMatrix::PLANE_FAR].center() + planes[1][CameraMatrix::PLANE_FAR].center()) * 0.5;
+ Plane far(-z, far_center);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Figure out our top/bottom planes
+
+ // 6. Intersect far and left planes with top planes from both eyes, save the point with highest y as top_left.
+ Vector3 top_left, other;
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[0][CameraMatrix::PLANE_LEFT], planes[0][CameraMatrix::PLANE_TOP], &top_left), "Can't determine left camera far/left/top vector");
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[1][CameraMatrix::PLANE_LEFT], planes[1][CameraMatrix::PLANE_TOP], &other), "Can't determine right camera far/left/top vector");
+ if (y.dot(top_left) < y.dot(other)) {
+ top_left = other;
+ }
+
+ // 7. Intersect far and left planes with bottom planes from both eyes, save the point with lowest y as bottom_left.
+ Vector3 bottom_left;
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[0][CameraMatrix::PLANE_LEFT], planes[0][CameraMatrix::PLANE_BOTTOM], &bottom_left), "Can't determine left camera far/left/bottom vector");
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[1][CameraMatrix::PLANE_LEFT], planes[1][CameraMatrix::PLANE_BOTTOM], &other), "Can't determine right camera far/left/bottom vector");
+ if (y.dot(other) < y.dot(bottom_left)) {
+ bottom_left = other;
+ }
+
+ // 8. Intersect far and right planes with top planes from both eyes, save the point with highest y as top_right.
+ Vector3 top_right;
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[0][CameraMatrix::PLANE_RIGHT], planes[0][CameraMatrix::PLANE_TOP], &top_right), "Can't determine left camera far/right/top vector");
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[1][CameraMatrix::PLANE_RIGHT], planes[1][CameraMatrix::PLANE_TOP], &other), "Can't determine right camera far/right/top vector");
+ if (y.dot(top_right) < y.dot(other)) {
+ top_right = other;
+ }
+
+ // 9. Intersect far and right planes with bottom planes from both eyes, save the point with lowest y as bottom_right.
+ Vector3 bottom_right;
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[0][CameraMatrix::PLANE_RIGHT], planes[0][CameraMatrix::PLANE_BOTTOM], &bottom_right), "Can't determine left camera far/right/bottom vector");
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[1][CameraMatrix::PLANE_RIGHT], planes[1][CameraMatrix::PLANE_BOTTOM], &other), "Can't determine right camera far/right/bottom vector");
+ if (y.dot(other) < y.dot(bottom_right)) {
+ bottom_right = other;
+ }
+
+ // 10. Create top plane with these points: camera origin, top_left, top_right
+ Plane top(main_transform.origin, top_left, top_right);
+
+ // 11. Create bottom plane with these points: camera origin, bottom_left, bottom_right
+ Plane bottom(main_transform.origin, bottom_left, bottom_right);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Figure out our near plane points
+
+ // 12. Create a near plane using -camera z and the eye further along in that axis.
+ Plane near;
+ Vector3 neg_z = -z;
+ if (neg_z.dot(p_transforms[1].origin) < neg_z.dot(p_transforms[0].origin)) {
+ near = Plane(neg_z, p_transforms[0].origin);
+ } else {
+ near = Plane(neg_z, p_transforms[1].origin);
+ }
+
+ // 13. Intersect near plane with bottm/left planes, to obtain min_vec then top/right to obtain max_vec
+ Vector3 min_vec;
+ ERR_FAIL_COND_MSG(
+ !near.intersect_3(bottom, planes[0][CameraMatrix::PLANE_LEFT], &min_vec), "Can't determine left camera near/left/bottom vector");
+ ERR_FAIL_COND_MSG(
+ !near.intersect_3(bottom, planes[1][CameraMatrix::PLANE_LEFT], &other), "Can't determine right camera near/left/bottom vector");
+ if (x.dot(other) < x.dot(min_vec)) {
+ min_vec = other;
+ }
+
+ Vector3 max_vec;
+ ERR_FAIL_COND_MSG(
+ !near.intersect_3(top, planes[0][CameraMatrix::PLANE_RIGHT], &max_vec), "Can't determine left camera near/right/top vector");
+ ERR_FAIL_COND_MSG(
+ !near.intersect_3(top, planes[1][CameraMatrix::PLANE_RIGHT], &other), "Can't determine right camera near/right/top vector");
+ if (x.dot(max_vec) < x.dot(other)) {
+ max_vec = other;
+ }
+
+ // 14. transform these points by the inverse camera to obtain local_min_vec and local_max_vec
+ Vector3 local_min_vec = main_transform_inv.xform(min_vec);
+ Vector3 local_max_vec = main_transform_inv.xform(max_vec);
+
+ // 15. get x and y from these to obtain left, top, right bottom for the frustum. Get the distance from near plane to camera origin to obtain near, and the distance from the far plane to the camer origin to obtain far.
+ float z_near = -near.distance_to(main_transform.origin);
+ float z_far = -far.distance_to(main_transform.origin);
+
+ // 16. Use this to build the combined camera matrix.
+ main_projection.set_frustum(local_min_vec.x, local_max_vec.x, local_min_vec.y, local_max_vec.y, z_near, z_far);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // 3. Copy our view data
+ for (uint32_t v = 0; v < view_count; v++) {
+ view_offset[v] = main_transform_inv * p_transforms[v];
+ view_projection[v] = p_projections[v] * CameraMatrix(view_offset[v].inverse());
+ }
+}
diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h
index 3f28fac549..0d71ea22da 100644
--- a/servers/rendering/renderer_scene_render.h
+++ b/servers/rendering/renderer_scene_render.h
@@ -33,13 +33,15 @@
#include "core/math/camera_matrix.h"
#include "core/templates/paged_array.h"
+#include "servers/rendering/renderer_scene.h"
#include "servers/rendering/renderer_storage.h"
class RendererSceneRender {
public:
enum {
MAX_DIRECTIONAL_LIGHTS = 8,
- MAX_DIRECTIONAL_LIGHT_CASCADES = 4
+ MAX_DIRECTIONAL_LIGHT_CASCADES = 4,
+ MAX_RENDER_VIEWS = 2
};
struct GeometryInstance {
@@ -51,9 +53,12 @@ public:
virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) = 0;
virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) = 0;
virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) = 0;
- virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) = 0;
+ virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) = 0;
virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) = 0;
virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) = 0;
+ virtual void geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) = 0;
+ virtual void geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) = 0;
+ virtual void geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) = 0;
virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) = 0;
virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) = 0;
virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) = 0;
@@ -65,7 +70,9 @@ public:
virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) = 0;
virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) = 0;
virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) = 0;
- virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) = 0;
+ virtual void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) = 0;
+
+ virtual void geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) = 0;
virtual void geometry_instance_free(GeometryInstance *p_geometry_instance) = 0;
@@ -109,7 +116,7 @@ public:
virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0;
virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0;
virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0;
- virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0;
+ virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) = 0;
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0;
@@ -119,7 +126,7 @@ public:
virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0;
virtual void environment_glow_set_use_high_quality(bool p_enable) = 0;
- virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) = 0;
+ virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) = 0;
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0;
virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0;
@@ -161,20 +168,26 @@ public:
virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) = 0;
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_transform(RID p_light_instance, const Transform3D &p_transform) = 0;
virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) = 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_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &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;
}
+ virtual RID fog_volume_instance_create(RID p_fog_volume) = 0;
+ virtual void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) = 0;
+ virtual void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) = 0;
+ virtual RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const = 0;
+ virtual Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const = 0;
+
virtual RID reflection_atlas_create() = 0;
virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0;
virtual int reflection_atlas_get_size(RID p_ref_atlas) const = 0;
virtual RID reflection_probe_instance_create(RID p_probe) = 0;
- virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) = 0;
+ virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0;
virtual void reflection_probe_release_atlas_index(RID p_instance) = 0;
virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0;
virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0;
@@ -182,17 +195,17 @@ public:
virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0;
virtual RID decal_instance_create(RID p_decal) = 0;
- virtual void decal_instance_set_transform(RID p_decal, const Transform &p_transform) = 0;
+ virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) = 0;
virtual RID lightmap_instance_create(RID p_lightmap) = 0;
- virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) = 0;
+ virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) = 0;
- virtual RID gi_probe_instance_create(RID p_gi_probe) = 0;
- virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0;
- virtual bool gi_probe_needs_update(RID p_probe) const = 0;
- virtual void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) = 0;
+ virtual RID voxel_gi_instance_create(RID p_voxel_gi) = 0;
+ virtual void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) = 0;
+ virtual bool voxel_gi_needs_update(RID p_probe) const = 0;
+ virtual void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) = 0;
- virtual void gi_probe_set_quality(RS::GIProbeQuality) = 0;
+ virtual void voxel_gi_set_quality(RS::VoxelGIQuality) = 0;
struct RenderShadowData {
RID light;
@@ -216,17 +229,34 @@ public:
uint32_t positional_light_count;
};
- virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) = 0;
+ struct CameraData {
+ // flags
+ uint32_t view_count;
+ bool is_ortogonal;
+ bool vaspect;
+
+ // Main/center projection
+ Transform3D main_transform;
+ CameraMatrix main_projection;
+
+ Transform3D view_offset[RendererSceneRender::MAX_RENDER_VIEWS];
+ CameraMatrix view_projection[RendererSceneRender::MAX_RENDER_VIEWS];
+
+ void set_camera(const Transform3D p_transform, const CameraMatrix p_projection, bool p_is_ortogonal, bool p_vaspect);
+ void set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const CameraMatrix *p_projections, bool p_is_ortogonal, bool p_vaspect);
+ };
+
+ virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) = 0;
- virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
- virtual void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) = 0;
+ virtual void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
+ virtual void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) = 0;
virtual void set_scene_pass(uint64_t p_pass) = 0;
virtual void set_time(double p_time, double p_step) = 0;
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, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) = 0;
+ virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0;
virtual void gi_set_use_half_resolution(bool p_enable) = 0;
virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0;
@@ -241,6 +271,9 @@ public:
virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0;
+ virtual void decals_set_filter(RS::DecalFilter p_filter) = 0;
+ virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) = 0;
+
virtual void update() = 0;
virtual ~RendererSceneRender() {}
};
diff --git a/servers/rendering/renderer_storage.cpp b/servers/rendering/renderer_storage.cpp
index a402ecc668..aa005fac0a 100644
--- a/servers/rendering/renderer_storage.cpp
+++ b/servers/rendering/renderer_storage.cpp
@@ -33,21 +33,21 @@
RendererStorage *RendererStorage::base_singleton = nullptr;
void RendererStorage::Dependency::changed_notify(DependencyChangedNotification p_notification) {
- for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
- if (E->key()->changed_callback) {
- E->key()->changed_callback(p_notification, E->key());
+ for (const KeyValue<DependencyTracker *, uint32_t> &E : instances) {
+ if (E.key->changed_callback) {
+ E.key->changed_callback(p_notification, E.key);
}
}
}
void RendererStorage::Dependency::deleted_notify(const RID &p_rid) {
- for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
- if (E->key()->deleted_callback) {
- E->key()->deleted_callback(p_rid, E->key());
+ for (const KeyValue<DependencyTracker *, uint32_t> &E : instances) {
+ if (E.key->deleted_callback) {
+ E.key->deleted_callback(p_rid, E.key);
}
}
- for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
- E->key()->dependencies.erase(this);
+ for (const KeyValue<DependencyTracker *, uint32_t> &E : instances) {
+ E.key->dependencies.erase(this);
}
instances.clear();
}
@@ -56,8 +56,8 @@ RendererStorage::Dependency::~Dependency() {
#ifdef DEBUG_ENABLED
if (instances.size()) {
WARN_PRINT("Leaked instance dependency: Bug - did not call instance_notify_deleted when freeing.");
- for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
- E->key()->dependencies.erase(this);
+ for (const KeyValue<DependencyTracker *, uint32_t> &E : instances) {
+ E.key->dependencies.erase(this);
}
}
#endif
diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h
index cc4ff5d55e..8926bf24aa 100644
--- a/servers/rendering/renderer_storage.h
+++ b/servers/rendering/renderer_storage.h
@@ -48,6 +48,7 @@ public:
DEPENDENCY_CHANGED_SKELETON_DATA,
DEPENDENCY_CHANGED_SKELETON_BONES,
DEPENDENCY_CHANGED_LIGHT,
+ DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR,
DEPENDENCY_CHANGED_REFLECTION_PROBE,
};
@@ -130,7 +131,6 @@ public:
virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) = 0;
virtual void texture_proxy_initialize(RID p_texture, RID p_base) = 0; //all slices, then all the mipmaps, must be coherent
- virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; //mostly used for video and streaming
virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0;
virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) = 0;
virtual void texture_proxy_update(RID p_proxy, RID p_base) = 0;
@@ -183,8 +183,8 @@ public:
virtual String shader_get_code(RID p_shader) const = 0;
virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0;
- virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0;
- virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0;
+ virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) = 0;
+ virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const = 0;
virtual Variant shader_get_param_default(RID p_material, const StringName &p_param) const = 0;
virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const = 0;
@@ -230,7 +230,9 @@ public:
virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) = 0;
virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const = 0;
- virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0;
+ virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0;
+ virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0;
+ virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0;
virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0;
virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0;
@@ -268,14 +270,14 @@ public:
virtual int multimesh_get_instance_count(RID p_multimesh) const = 0;
virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0;
- virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) = 0;
+ virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) = 0;
virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0;
virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0;
virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0;
virtual RID multimesh_get_mesh(RID p_multimesh) const = 0;
- virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0;
+ virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0;
virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0;
virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0;
virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0;
@@ -288,24 +290,6 @@ public:
virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0;
- /* IMMEDIATE API */
-
- virtual RID immediate_allocate() = 0;
- virtual void immediate_initialize(RID p_rid) = 0;
-
- virtual void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) = 0;
- virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) = 0;
- virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal) = 0;
- virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) = 0;
- virtual void immediate_color(RID p_immediate, const Color &p_color) = 0;
- virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) = 0;
- virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) = 0;
- virtual void immediate_end(RID p_immediate) = 0;
- virtual void immediate_clear(RID p_immediate) = 0;
- virtual void immediate_set_material(RID p_immediate, RID p_material) = 0;
- virtual RID immediate_get_material(RID p_immediate) const = 0;
- virtual AABB immediate_get_aabb(RID p_immediate) const = 0;
-
/* SKELETON API */
virtual RID skeleton_allocate() = 0;
@@ -313,8 +297,8 @@ public:
virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0;
virtual int skeleton_get_bone_count(RID p_skeleton) const = 0;
- virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) = 0;
- virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0;
+ virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) = 0;
+ virtual Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0;
virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0;
virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0;
virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0;
@@ -348,14 +332,14 @@ public:
virtual bool light_directional_get_blend_splits(RID p_light) const = 0;
virtual void light_directional_set_sky_only(RID p_light, bool p_sky_only) = 0;
virtual bool light_directional_is_sky_only(RID p_light) const = 0;
- virtual void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) = 0;
- virtual RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const = 0;
virtual RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) = 0;
virtual RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) = 0;
virtual bool light_has_shadow(RID p_light) const = 0;
+ virtual bool light_has_projector(RID p_light) const = 0;
+
virtual RS::LightType light_get_type(RID p_light) const = 0;
virtual AABB light_get_aabb(RID p_light) const = 0;
virtual float light_get_param(RID p_light, RS::LightParam p_param) = 0;
@@ -413,53 +397,47 @@ public:
virtual AABB decal_get_aabb(RID p_decal) const = 0;
- /* GI PROBE API */
+ /* VOXEL GI API */
- virtual RID gi_probe_allocate() = 0;
- virtual void gi_probe_initialize(RID p_rid) = 0;
+ virtual RID voxel_gi_allocate() = 0;
+ virtual void voxel_gi_initialize(RID p_rid) = 0;
- virtual void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0;
+ virtual void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0;
- virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0;
- virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0;
- virtual Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0;
- virtual Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0;
- virtual Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const = 0;
+ virtual AABB voxel_gi_get_bounds(RID p_voxel_gi) const = 0;
+ virtual Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const = 0;
+ virtual Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const = 0;
+ virtual Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const = 0;
+ virtual Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const = 0;
- virtual Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0;
- virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0;
+ virtual Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const = 0;
+ virtual Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const = 0;
- virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) = 0;
- virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const = 0;
+ virtual void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) = 0;
+ virtual float voxel_gi_get_dynamic_range(RID p_voxel_gi) const = 0;
- virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) = 0;
- virtual float gi_probe_get_propagation(RID p_gi_probe) const = 0;
+ virtual void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) = 0;
+ virtual float voxel_gi_get_propagation(RID p_voxel_gi) const = 0;
- virtual void gi_probe_set_energy(RID p_gi_probe, float p_energy) = 0;
- virtual float gi_probe_get_energy(RID p_gi_probe) const = 0;
+ virtual void voxel_gi_set_energy(RID p_voxel_gi, float p_energy) = 0;
+ virtual float voxel_gi_get_energy(RID p_voxel_gi) const = 0;
- virtual void gi_probe_set_ao(RID p_gi_probe, float p_ao) = 0;
- virtual float gi_probe_get_ao(RID p_gi_probe) const = 0;
+ virtual void voxel_gi_set_bias(RID p_voxel_gi, float p_bias) = 0;
+ virtual float voxel_gi_get_bias(RID p_voxel_gi) const = 0;
- virtual void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) = 0;
- virtual float gi_probe_get_ao_size(RID p_gi_probe) const = 0;
+ virtual void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) = 0;
+ virtual float voxel_gi_get_normal_bias(RID p_voxel_gi) const = 0;
- virtual void gi_probe_set_bias(RID p_gi_probe, float p_bias) = 0;
- virtual float gi_probe_get_bias(RID p_gi_probe) const = 0;
+ virtual void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) = 0;
+ virtual bool voxel_gi_is_interior(RID p_voxel_gi) const = 0;
- virtual void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) = 0;
- virtual float gi_probe_get_normal_bias(RID p_gi_probe) const = 0;
+ virtual void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) = 0;
+ virtual bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const = 0;
- virtual void gi_probe_set_interior(RID p_gi_probe, bool p_enable) = 0;
- virtual bool gi_probe_is_interior(RID p_gi_probe) const = 0;
+ virtual void voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) = 0;
+ virtual float voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const = 0;
- virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) = 0;
- virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) = 0;
- virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const = 0;
-
- virtual uint32_t gi_probe_get_version(RID p_probe) = 0;
+ virtual uint32_t voxel_gi_get_version(RID p_probe) = 0;
/* LIGHTMAP */
@@ -490,27 +468,27 @@ public:
virtual bool particles_get_emitting(RID p_particles) = 0;
virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
- virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0;
+ virtual void particles_set_lifetime(RID p_particles, double p_lifetime) = 0;
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0;
- virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0;
- virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0;
- virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0;
+ virtual void particles_set_pre_process_time(RID p_particles, double p_time) = 0;
+ virtual void particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) = 0;
+ virtual void particles_set_randomness_ratio(RID p_particles, real_t p_ratio) = 0;
virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) = 0;
- virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0;
+ virtual void particles_set_speed_scale(RID p_particles, double p_scale) = 0;
virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0;
virtual void particles_set_process_material(RID p_particles, RID p_material) = 0;
virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
virtual void particles_set_interpolate(RID p_particles, bool p_enable) = 0;
virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
- virtual void particles_set_collision_base_size(RID p_particles, float p_size) = 0;
+ virtual void particles_set_collision_base_size(RID p_particles, real_t p_size) = 0;
virtual void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) = 0;
- virtual void particles_set_trails(RID p_particles, bool p_enable, float p_length) = 0;
- virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses) = 0;
+ virtual void particles_set_trails(RID p_particles, bool p_enable, double p_length) = 0;
+ virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) = 0;
virtual void particles_restart(RID p_particles) = 0;
- virtual void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0;
+ virtual void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0;
virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) = 0;
virtual bool particles_is_inactive(RID p_particles) const = 0;
@@ -524,7 +502,7 @@ public:
virtual AABB particles_get_current_aabb(RID p_particles) = 0;
virtual AABB particles_get_aabb(RID p_particles) const = 0;
- virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0;
+ virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) = 0;
virtual int particles_get_draw_passes(RID p_particles) const = 0;
virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const = 0;
@@ -534,6 +512,8 @@ public:
virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance) = 0;
virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance) = 0;
+ virtual void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) = 0;
+
virtual void update_particles() = 0;
/* PARTICLES COLLISION */
@@ -543,11 +523,11 @@ public:
virtual void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) = 0;
virtual void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) = 0;
- virtual void particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) = 0; //for spheres
+ virtual void particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) = 0; //for spheres
virtual void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) = 0; //for non-spheres
- virtual void particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength) = 0;
- virtual void particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality) = 0;
- virtual void particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve) = 0;
+ virtual void particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) = 0;
+ virtual void particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) = 0;
+ virtual void particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) = 0;
virtual void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) = 0; //for SDF and vector field, heightfield is dynamic
virtual void particles_collision_height_field_update(RID p_particles_collision) = 0; //for SDF and vector field
virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) = 0; //for SDF and vector field
@@ -555,9 +535,30 @@ public:
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0;
virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const = 0;
+ /* FOG VOLUMES */
+
+ virtual RID fog_volume_allocate() = 0;
+ virtual void fog_volume_initialize(RID p_rid) = 0;
+
+ virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) = 0;
+ virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) = 0;
+ virtual void fog_volume_set_material(RID p_fog_volume, RID p_material) = 0;
+ virtual AABB fog_volume_get_aabb(RID p_fog_volume) const = 0;
+ virtual RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const = 0;
+
+ /* VISIBILITY NOTIFIER */
+
+ virtual RID visibility_notifier_allocate() = 0;
+ virtual void visibility_notifier_initialize(RID p_notifier) = 0;
+ virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) = 0;
+ virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) = 0;
+
+ virtual AABB visibility_notifier_get_aabb(RID p_notifier) const = 0;
+ virtual void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) = 0;
+
//used from 2D and 3D
virtual RID particles_collision_instance_create(RID p_collision) = 0;
- virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) = 0;
+ virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) = 0;
virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) = 0;
/* GLOBAL VARIABLES */
@@ -588,7 +589,7 @@ public:
virtual RID render_target_create() = 0;
virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) = 0;
- virtual void render_target_set_size(RID p_render_target, int p_width, int p_height) = 0;
+ virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) = 0;
virtual RID render_target_get_texture(RID p_render_target) = 0;
virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0;
virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0;
@@ -603,6 +604,7 @@ public:
virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) = 0;
virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const = 0;
+ virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) = 0;
virtual RS::InstanceType get_base_type(RID p_rid) const = 0;
virtual bool free(RID p_rid) = 0;
@@ -613,11 +615,9 @@ public:
virtual void set_debug_generate_wireframes(bool p_generate) = 0;
- virtual void render_info_begin_capture() = 0;
- virtual void render_info_end_capture() = 0;
- virtual int get_captured_render_info(RS::RenderInfo p_info) = 0;
+ virtual void update_memory_info() = 0;
- virtual uint64_t get_render_info(RS::RenderInfo p_info) = 0;
+ virtual uint64_t get_rendering_info(RS::RenderingInfo p_info) = 0;
virtual String get_video_adapter_name() const = 0;
virtual String get_video_adapter_vendor() const = 0;
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index f7be6c6c60..eddf5bf53d 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -71,11 +71,84 @@ static Transform2D _canvas_get_transform(RendererViewport::Viewport *p_viewport,
return xf;
}
-void RendererViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) {
+void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
+ if (p_viewport->render_buffers.is_valid()) {
+ if (p_viewport->size.width == 0 || p_viewport->size.height == 0) {
+ RSG::scene->free(p_viewport->render_buffers);
+ p_viewport->render_buffers = RID();
+ } else {
+ float scaling_3d_scale = p_viewport->scaling_3d_scale;
+
+ RS::ViewportScaling3DMode scaling_3d_mode = p_viewport->scaling_3d_mode;
+ bool scaling_enabled = true;
+
+ if ((scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && (scaling_3d_scale > 1.0)) {
+ // FSR is not design for downsampling.
+ // Throw a warning and fallback to VIEWPORT_SCALING_3D_MODE_BILINEAR
+ WARN_PRINT_ONCE("FSR 3D resolution scaling does not support supersampling. Falling back to bilinear scaling.");
+ scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
+ }
+
+ if ((scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && !p_viewport->fsr_enabled) {
+ // FSR is not actually available.
+ // Throw a warning and fallback to disable scaling
+ WARN_PRINT_ONCE("FSR 3D resolution scaling is not available. Disabling 3D resolution scaling.");
+ scaling_enabled = false;
+ }
+
+ if (scaling_3d_scale == 1.0) {
+ scaling_enabled = false;
+ }
+
+ int width;
+ int height;
+ int render_width;
+ int render_height;
+
+ if (scaling_enabled) {
+ switch (scaling_3d_mode) {
+ case RS::VIEWPORT_SCALING_3D_MODE_BILINEAR:
+ // Clamp 3D rendering resolution to reasonable values supported on most hardware.
+ // This prevents freezing the engine or outright crashing on lower-end GPUs.
+ width = CLAMP(p_viewport->size.width * scaling_3d_scale, 1, 16384);
+ height = CLAMP(p_viewport->size.height * scaling_3d_scale, 1, 16384);
+ render_width = width;
+ render_height = height;
+ break;
+ case RS::VIEWPORT_SCALING_3D_MODE_FSR:
+ width = p_viewport->size.width;
+ height = p_viewport->size.height;
+ render_width = MAX(width * scaling_3d_scale, 1.0); // width / (width * scaling)
+ render_height = MAX(height * scaling_3d_scale, 1.0);
+ break;
+ default:
+ // This is an unknown mode.
+ WARN_PRINT_ONCE(vformat("Unknown scaling mode: %d. Disabling 3D resolution scaling.", scaling_3d_mode));
+ width = p_viewport->size.width;
+ height = p_viewport->size.height;
+ render_width = width;
+ render_height = height;
+ break;
+ }
+ } else {
+ width = p_viewport->size.width;
+ height = p_viewport->size.height;
+ render_width = width;
+ render_height = height;
+ }
+
+ p_viewport->internal_size = Size2(render_width, render_height);
+
+ RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, render_width, render_height, width, height, p_viewport->fsr_sharpness, p_viewport->fsr_mipmap_bias, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_debanding, p_viewport->get_view_count());
+ }
+ }
+}
+
+void RendererViewport::_draw_3d(Viewport *p_viewport) {
RENDER_TIMESTAMP(">Begin Rendering 3D Scene");
Ref<XRInterface> xr_interface;
- if (XRServer::get_singleton() != nullptr) {
+ if (p_viewport->use_xr && XRServer::get_singleton() != nullptr) {
xr_interface = XRServer::get_singleton()->get_primary_interface();
}
@@ -95,29 +168,37 @@ void RendererViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) {
}
float screen_lod_threshold = p_viewport->lod_threshold / float(p_viewport->size.width);
- if (p_viewport->use_xr && xr_interface.is_valid()) {
- RSG::scene->render_camera(p_viewport->render_buffers, xr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas);
- } else {
- RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas);
- }
+ RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->internal_size, screen_lod_threshold, p_viewport->shadow_atlas, xr_interface, &p_viewport->render_info);
+
RENDER_TIMESTAMP("<End Rendering 3D Scene");
}
-void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye) {
+void RendererViewport::_draw_viewport(Viewport *p_viewport) {
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;
}
+ if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3") {
+ // This is currently needed for GLES to keep the current window being rendered to up to date
+ DisplayServer::get_singleton()->gl_window_make_current(p_viewport->viewport_to_screen);
+ }
+
/* 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
int scenario_canvas_max_layer = 0;
+ for (int i = 0; i < RS::VIEWPORT_RENDER_INFO_TYPE_MAX; i++) {
+ for (int j = 0; j < RS::VIEWPORT_RENDER_INFO_MAX; j++) {
+ p_viewport->render_info.info[i][j] = 0;
+ }
+ }
+
Color bgcolor = RSG::storage->get_default_clear_color();
- if (!p_viewport->hide_canvas && !p_viewport->disable_environment && RSG::scene->is_scenario(p_viewport->scenario)) {
+ if (!p_viewport->disable_2d && !p_viewport->disable_environment && RSG::scene->is_scenario(p_viewport->scenario)) {
RID environment = RSG::scene->scenario_get_environment(p_viewport->scenario);
if (RSG::scene->is_environment(environment)) {
scenario_draw_canvas_bg = RSG::scene->environment_get_background(environment) == RS::ENV_BG_CANVAS;
@@ -125,7 +206,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
}
}
- bool can_draw_3d = RSG::scene->is_camera(p_viewport->camera);
+ bool can_draw_3d = RSG::scene->is_camera(p_viewport->camera) && !p_viewport->disable_3d;
if (p_viewport->clear_mode != RS::VIEWPORT_CLEAR_NEVER) {
if (p_viewport->transparent_bg) {
@@ -139,16 +220,17 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
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_buffers_create();
- RSG::scene->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, p_viewport->use_debanding);
+
+ _configure_3d_render_buffers(p_viewport);
}
RSG::storage->render_target_request_clear(p_viewport->render_target, bgcolor);
if (!scenario_draw_canvas_bg && can_draw_3d) {
- _draw_3d(p_viewport, p_eye);
+ _draw_3d(p_viewport);
}
- if (!p_viewport->hide_canvas) {
+ if (!p_viewport->disable_2d) {
int i = 0;
Map<Viewport::CanvasKey, Viewport::CanvasData *> canvas_map;
@@ -168,9 +250,9 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
RendererCanvasRender::LightOccluderInstance *occluders = nullptr;
//make list of occluders
- for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) {
- RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas);
- Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size);
+ for (KeyValue<RID, Viewport::CanvasData> &E : p_viewport->canvas_map) {
+ RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value.canvas);
+ Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E.value, clip_rect.size);
for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) {
if (!F->get()->enabled) {
@@ -186,8 +268,11 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
}
RSG::canvas_render->render_sdf(p_viewport->render_target, occluders);
+ RSG::storage->render_target_mark_sdf_enabled(p_viewport->render_target, true);
p_viewport->sdf_active = false; // if used, gets set active again
+ } else {
+ RSG::storage->render_target_mark_sdf_enabled(p_viewport->render_target, false);
}
Rect2 shadow_rect;
@@ -197,10 +282,10 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
int directional_light_count = 0;
RENDER_TIMESTAMP("Cull Canvas Lights");
- for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) {
- RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas);
+ for (KeyValue<RID, Viewport::CanvasData> &E : p_viewport->canvas_map) {
+ RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value.canvas);
- Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size);
+ Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E.value, clip_rect.size);
//find lights in canvas
@@ -262,7 +347,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
}
}
- canvas_map[Viewport::CanvasKey(E->key(), E->get().layer, E->get().sublayer)] = &E->get();
+ canvas_map[Viewport::CanvasKey(E.key, E.value.layer, E.value.sublayer)] = &E.value;
}
if (lights_with_shadow) {
@@ -274,9 +359,9 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
RENDER_TIMESTAMP("Cull Occluders");
//make list of occluders
- for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) {
- RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas);
- Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size);
+ for (KeyValue<RID, Viewport::CanvasData> &E : p_viewport->canvas_map) {
+ RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value.canvas);
+ Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E.value, clip_rect.size);
for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) {
if (!F->get()->enabled) {
@@ -322,7 +407,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
Vector2 point = clip_rect.position + clip_rect.size * signs[j];
if (sign_cmp == light_dir_sign) {
- //both point in same direction, plot offseted
+ //both point in same direction, plot offsetted
points[point_count++] = point + light_dir * cull_distance;
} else if (sign_cmp.x == light_dir_sign.x || sign_cmp.y == light_dir_sign.y) {
int next_j = (j + 1) % 4;
@@ -355,9 +440,9 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
//make list of occluders
int occ_cullded = 0;
- for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) {
- RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas);
- Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size);
+ for (KeyValue<RID, Viewport::CanvasData> &E : p_viewport->canvas_map) {
+ RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value.canvas);
+ Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E.value, clip_rect.size);
for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) {
if (!F->get()->enabled) {
@@ -389,22 +474,22 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
if (!can_draw_3d) {
RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas);
} else {
- _draw_3d(p_viewport, p_eye);
+ _draw_3d(p_viewport);
}
scenario_draw_canvas_bg = false;
}
- for (Map<Viewport::CanvasKey, Viewport::CanvasData *>::Element *E = canvas_map.front(); E; E = E->next()) {
- RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get()->canvas);
+ for (const KeyValue<Viewport::CanvasKey, Viewport::CanvasData *> &E : canvas_map) {
+ RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value->canvas);
- Transform2D xform = _canvas_get_transform(p_viewport, canvas, E->get(), clip_rect.size);
+ Transform2D xform = _canvas_get_transform(p_viewport, canvas, E.value, clip_rect.size);
RendererCanvasRender::Light *canvas_lights = nullptr;
RendererCanvasRender::Light *canvas_directional_lights = nullptr;
RendererCanvasRender::Light *ptr = lights;
while (ptr) {
- if (E->get()->layer >= ptr->layer_min && E->get()->layer <= ptr->layer_max) {
+ if (E.value->layer >= ptr->layer_min && E.value->layer <= ptr->layer_max) {
ptr->next_ptr = canvas_lights;
canvas_lights = ptr;
}
@@ -413,7 +498,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
ptr = directional_lights;
while (ptr) {
- if (E->get()->layer >= ptr->layer_min && E->get()->layer <= ptr->layer_max) {
+ if (E.value->layer >= ptr->layer_min && E.value->layer <= ptr->layer_max) {
ptr->next_ptr = canvas_directional_lights;
canvas_directional_lights = ptr;
}
@@ -426,11 +511,11 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
}
i++;
- if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) {
+ if (scenario_draw_canvas_bg && E.key.get_layer() >= scenario_canvas_max_layer) {
if (!can_draw_3d) {
RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas);
} else {
- _draw_3d(p_viewport, p_eye);
+ _draw_3d(p_viewport);
}
scenario_draw_canvas_bg = false;
@@ -441,7 +526,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
if (!can_draw_3d) {
RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas);
} else {
- _draw_3d(p_viewport, p_eye);
+ _draw_3d(p_viewport);
}
}
}
@@ -466,9 +551,6 @@ void RendererViewport::draw_viewports() {
if (XRServer::get_singleton() != nullptr) {
xr_interface = XRServer::get_singleton()->get_primary_interface();
-
- // process all our active interfaces
- XRServer::get_singleton()->_process();
}
if (Engine::get_singleton()->is_editor_hint()) {
@@ -478,7 +560,7 @@ void RendererViewport::draw_viewports() {
//sort viewports
active_viewports.sort_custom<ViewportSort>();
- Map<DisplayServer::WindowID, Vector<RendererCompositor::BlitToScreen>> blit_to_screen_list;
+ Map<DisplayServer::WindowID, Vector<BlitToScreen>> blit_to_screen_list;
//draw viewports
RENDER_TIMESTAMP(">Render Viewports");
@@ -509,7 +591,7 @@ void RendererViewport::draw_viewports() {
}
if (vp->update_mode == RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE) {
- Viewport *parent = viewport_owner.getornull(vp->parent);
+ Viewport *parent = viewport_owner.get_or_null(vp->parent);
if (parent && parent->last_pass == draw_viewports_pass) {
visible = true;
}
@@ -522,6 +604,10 @@ void RendererViewport::draw_viewports() {
}
}
+ int vertices_drawn = 0;
+ int objects_drawn = 0;
+ int draw_calls_used = 0;
+
for (int i = 0; i < active_viewports.size(); i++) {
Viewport *vp = active_viewports[i];
@@ -532,74 +618,59 @@ void RendererViewport::draw_viewports() {
RENDER_TIMESTAMP(">Rendering Viewport " + itos(i));
RSG::storage->render_target_set_as_unused(vp->render_target);
-#if 0
- // TODO fix up this code after we change our commit_for_eye to accept our new render targets
-
if (vp->use_xr && xr_interface.is_valid()) {
- // override our size, make sure it matches our required size
- vp->size = xr_interface->get_render_targetsize();
- RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y);
-
- // render mono or left eye first
- XRInterface::Eyes leftOrMono = xr_interface->is_stereo() ? XRInterface::EYE_LEFT : XRInterface::EYE_MONO;
+ // override our size, make sure it matches our required size and is created as a stereo target
+ vp->size = xr_interface->get_render_target_size();
+ uint32_t view_count = xr_interface->get_view_count();
+ RSG::storage->render_target_set_size(vp->render_target, vp->internal_size.x, vp->internal_size.y, view_count);
- // check for an external texture destination for our left eye/mono
- // TODO investigate how we're going to make external textures work
- RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(leftOrMono));
+ // check for an external texture destination (disabled for now, not yet supported)
+ // RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(leftOrMono));
+ RSG::storage->render_target_set_external_texture(vp->render_target, 0);
- // set our render target as current
- RSG::rasterizer->set_current_render_target(vp->render_target);
+ // render...
+ RSG::scene->set_debug_draw_mode(vp->debug_draw);
- // and draw left eye/mono
- _draw_viewport(vp, leftOrMono);
- xr_interface->commit_for_eye(leftOrMono, vp->render_target, vp->viewport_to_screen_rect);
+ // and draw viewport
+ _draw_viewport(vp);
- // render right eye
- if (leftOrMono == XRInterface::EYE_LEFT) {
- // check for an external texture destination for our right eye
- RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(XRInterface::EYE_RIGHT));
+ // measure
- // commit for eye may have changed the render target
- RSG::rasterizer->set_current_render_target(vp->render_target);
+ // commit our eyes
+ Vector<BlitToScreen> blits = xr_interface->commit_views(vp->render_target, vp->viewport_to_screen_rect);
+ if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && blits.size() > 0) {
+ if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
+ blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
+ }
- _draw_viewport(vp, XRInterface::EYE_RIGHT);
- xr_interface->commit_for_eye(XRInterface::EYE_RIGHT, vp->render_target, vp->viewport_to_screen_rect);
+ for (int b = 0; b < blits.size(); b++) {
+ blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]);
+ }
}
// and for our frame timing, mark when we've finished committing our eyes
XRServer::get_singleton()->_mark_commit();
} else {
-#endif
- {
RSG::storage->render_target_set_external_texture(vp->render_target, 0);
RSG::scene->set_debug_draw_mode(vp->debug_draw);
- RSG::storage->render_info_begin_capture();
// render standard mono camera
_draw_viewport(vp);
- RSG::storage->render_info_end_capture();
- vp->render_info[RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_OBJECTS_IN_FRAME);
- vp->render_info[RS::VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_VERTICES_IN_FRAME);
- vp->render_info[RS::VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_MATERIAL_CHANGES_IN_FRAME);
- vp->render_info[RS::VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_SHADER_CHANGES_IN_FRAME);
- vp->render_info[RS::VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_SURFACE_CHANGES_IN_FRAME);
- vp->render_info[RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_DRAW_CALLS_IN_FRAME);
-
if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && (!vp->viewport_render_direct_to_screen || !RSG::rasterizer->is_low_end())) {
//copy to screen if set as such
- RendererCompositor::BlitToScreen blit;
+ BlitToScreen blit;
blit.render_target = vp->render_target;
if (vp->viewport_to_screen_rect != Rect2()) {
- blit.rect = vp->viewport_to_screen_rect;
+ blit.dst_rect = vp->viewport_to_screen_rect;
} else {
- blit.rect.position = Vector2();
- blit.rect.size = vp->size;
+ blit.dst_rect.position = Vector2();
+ blit.dst_rect.size = vp->size;
}
if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
- blit_to_screen_list[vp->viewport_to_screen] = Vector<RendererCompositor::BlitToScreen>();
+ blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
}
blit_to_screen_list[vp->viewport_to_screen].push_back(blit);
@@ -611,15 +682,23 @@ void RendererViewport::draw_viewports() {
}
RENDER_TIMESTAMP("<Rendering Viewport " + itos(i));
+
+ objects_drawn += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] + vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME];
+ vertices_drawn += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] + vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME];
+ draw_calls_used += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] + vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME];
}
RSG::scene->set_debug_draw_mode(RS::VIEWPORT_DEBUG_DRAW_DISABLED);
+ total_objects_drawn = objects_drawn;
+ total_vertices_drawn = vertices_drawn;
+ total_draw_calls_used = draw_calls_used;
+
RENDER_TIMESTAMP("<Render Viewports");
//this needs to be called to make screen swapping more efficient
RSG::rasterizer->prepare_for_blitting_render_targets();
- for (Map<int, Vector<RendererCompositor::BlitToScreen>>::Element *E = blit_to_screen_list.front(); E; E = E->next()) {
- RSG::rasterizer->blit_render_targets_to_screen(E->key(), E->get().ptr(), E->get().size());
+ for (const KeyValue<int, Vector<BlitToScreen>> &E : blit_to_screen_list) {
+ RSG::rasterizer->blit_render_targets_to_screen(E.key, E.value.ptr(), E.value.size());
}
}
@@ -628,50 +707,103 @@ RID RendererViewport::viewport_allocate() {
}
void RendererViewport::viewport_initialize(RID p_rid) {
- Viewport *viewport = memnew(Viewport);
+ viewport_owner.initialize_rid(p_rid);
+ Viewport *viewport = viewport_owner.get_or_null(p_rid);
viewport->self = p_rid;
- viewport->hide_scenario = false;
- viewport->hide_canvas = false;
viewport->render_target = RSG::storage->render_target_create();
viewport->shadow_atlas = RSG::scene->shadow_atlas_create();
viewport->viewport_render_direct_to_screen = false;
- viewport_owner.initialize_rid(p_rid, viewport);
+ viewport->fsr_enabled = !RSG::rasterizer->is_low_end() && !viewport->disable_3d;
}
void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
+ if (viewport->use_xr == p_use_xr) {
+ return;
+ }
+
viewport->use_xr = p_use_xr;
+ _configure_3d_render_buffers(viewport);
+}
+
+void RendererViewport::viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode) {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->scaling_3d_mode = p_mode;
+ _configure_3d_render_buffers(viewport);
+}
+
+void RendererViewport::viewport_set_fsr_sharpness(RID p_viewport, float p_sharpness) {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->fsr_sharpness = p_sharpness;
+ _configure_3d_render_buffers(viewport);
+}
+
+void RendererViewport::viewport_set_fsr_mipmap_bias(RID p_viewport, float p_mipmap_bias) {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->fsr_mipmap_bias = p_mipmap_bias;
+ _configure_3d_render_buffers(viewport);
+}
+
+void RendererViewport::viewport_set_scaling_3d_scale(RID p_viewport, float p_scaling_3d_scale) {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ // Clamp to reasonable values that are actually useful.
+ // Values above 2.0 don't serve a practical purpose since the viewport
+ // isn't displayed with mipmaps.
+ if (viewport->scaling_3d_scale == CLAMP(p_scaling_3d_scale, 0.1, 2.0)) {
+ return;
+ }
+
+ viewport->scaling_3d_scale = CLAMP(p_scaling_3d_scale, 0.1, 2.0);
+ _configure_3d_render_buffers(viewport);
+}
+
+uint32_t RendererViewport::Viewport::get_view_count() {
+ uint32_t view_count = 1;
+
+ if (use_xr && XRServer::get_singleton() != nullptr) {
+ Ref<XRInterface> xr_interface;
+
+ xr_interface = XRServer::get_singleton()->get_primary_interface();
+ if (xr_interface.is_valid()) {
+ view_count = xr_interface->get_view_count();
+ }
+ }
+
+ return view_count;
}
void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) {
ERR_FAIL_COND(p_width < 0 && p_height < 0);
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
viewport->size = Size2(p_width, p_height);
- RSG::storage->render_target_set_size(viewport->render_target, p_width, p_height);
- if (viewport->render_buffers.is_valid()) {
- if (p_width == 0 || p_height == 0) {
- RSG::scene->free(viewport->render_buffers);
- viewport->render_buffers = RID();
- } else {
- RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, viewport->use_debanding);
- }
- }
+
+ uint32_t view_count = viewport->get_view_count();
+ RSG::storage->render_target_set_size(viewport->render_target, p_width, p_height, view_count);
+ _configure_3d_render_buffers(viewport);
viewport->occlusion_buffer_dirty = true;
}
void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
if (p_active) {
- ERR_FAIL_COND(active_viewports.find(viewport) != -1); //already active
+ ERR_FAIL_COND_MSG(active_viewports.find(viewport) != -1, "Can't make active a Viewport that is already active.");
viewport->occlusion_buffer_dirty = true;
active_viewports.push_back(viewport);
} else {
@@ -680,28 +812,28 @@ void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) {
}
void RendererViewport::viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
viewport->parent = p_parent_viewport;
}
void RendererViewport::viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
viewport->clear_mode = p_clear_mode;
}
void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect, DisplayServer::WindowID p_screen) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
if (p_screen != DisplayServer::INVALID_WINDOW_ID) {
- // If using GLES2 we can optimize this operation by rendering directly to system_fbo
+ // If using OpenGL we can optimize this operation by rendering directly to system_fbo
// instead of rendering to fbo and copying to system_fbo after
if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
- RSG::storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y);
+ RSG::storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y, viewport->get_view_count());
RSG::storage->render_target_set_position(viewport->render_target, p_rect.position.x, p_rect.position.y);
}
@@ -711,7 +843,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_
// if render_direct_to_screen was used, reset size and position
if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
RSG::storage->render_target_set_position(viewport->render_target, 0, 0);
- RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y);
+ RSG::storage->render_target_set_size(viewport->render_target, viewport->internal_size.x, viewport->internal_size.y, viewport->get_view_count());
}
viewport->viewport_to_screen_rect = Rect2();
@@ -720,7 +852,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_
}
void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
if (p_enable == viewport->viewport_render_direct_to_screen) {
@@ -730,7 +862,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool
// if disabled, reset render_target size and position
if (!p_enable) {
RSG::storage->render_target_set_position(viewport->render_target, 0, 0);
- RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y);
+ RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count());
}
RSG::storage->render_target_set_flag(viewport->render_target, RendererStorage::RENDER_TARGET_DIRECT_TO_SCREEN, p_enable);
@@ -738,27 +870,27 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool
// if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unnecessary buffer allocation
if (RSG::rasterizer->is_low_end() && viewport->viewport_to_screen_rect != Rect2() && p_enable) {
- RSG::storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y);
+ RSG::storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y, viewport->get_view_count());
RSG::storage->render_target_set_position(viewport->render_target, viewport->viewport_to_screen_rect.position.x, viewport->viewport_to_screen_rect.position.y);
}
}
void RendererViewport::viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
viewport->update_mode = p_mode;
}
RID RendererViewport::viewport_get_texture(RID p_viewport) const {
- const Viewport *viewport = viewport_owner.getornull(p_viewport);
+ const Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND_V(!viewport, RID());
return RSG::storage->render_target_get_texture(viewport->render_target);
}
RID RendererViewport::viewport_get_occluder_debug_texture(RID p_viewport) const {
- const Viewport *viewport = viewport_owner.getornull(p_viewport);
+ const Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND_V(!viewport, RID());
if (viewport->use_occlusion_culling && viewport->debug_draw == RenderingServer::VIEWPORT_DEBUG_DRAW_OCCLUDERS) {
@@ -767,38 +899,42 @@ RID RendererViewport::viewport_get_occluder_debug_texture(RID p_viewport) const
return RID();
}
-void RendererViewport::viewport_set_hide_scenario(RID p_viewport, bool p_hide) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+void RendererViewport::viewport_set_disable_2d(RID p_viewport, bool p_disable) {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
- viewport->hide_scenario = p_hide;
+ viewport->disable_2d = p_disable;
}
-void RendererViewport::viewport_set_hide_canvas(RID p_viewport, bool p_hide) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+void RendererViewport::viewport_set_disable_environment(RID p_viewport, bool p_disable) {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
- viewport->hide_canvas = p_hide;
+ viewport->disable_environment = p_disable;
}
-void RendererViewport::viewport_set_disable_environment(RID p_viewport, bool p_disable) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+void RendererViewport::viewport_set_disable_3d(RID p_viewport, bool p_disable) {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
- viewport->disable_environment = p_disable;
+ viewport->disable_3d = p_disable;
}
void RendererViewport::viewport_attach_camera(RID p_viewport, RID p_camera) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
viewport->camera = p_camera;
}
void RendererViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
+ if (viewport->scenario.is_valid()) {
+ RSG::scene->scenario_remove_viewport_visibility_mask(viewport->scenario, p_viewport);
+ }
+
viewport->scenario = p_scenario;
if (viewport->use_occlusion_culling) {
RendererSceneOcclusionCull::get_singleton()->buffer_set_scenario(p_viewport, p_scenario);
@@ -806,11 +942,11 @@ void RendererViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) {
}
void RendererViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
ERR_FAIL_COND(viewport->canvas_map.has(p_canvas));
- RendererCanvasCull::Canvas *canvas = RSG::canvas->canvas_owner.getornull(p_canvas);
+ RendererCanvasCull::Canvas *canvas = RSG::canvas->canvas_owner.get_or_null(p_canvas);
ERR_FAIL_COND(!canvas);
canvas->viewports.insert(p_viewport);
@@ -821,10 +957,10 @@ void RendererViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) {
}
void RendererViewport::viewport_remove_canvas(RID p_viewport, RID p_canvas) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
- RendererCanvasCull::Canvas *canvas = RSG::canvas->canvas_owner.getornull(p_canvas);
+ RendererCanvasCull::Canvas *canvas = RSG::canvas->canvas_owner.get_or_null(p_canvas);
ERR_FAIL_COND(!canvas);
viewport->canvas_map.erase(p_canvas);
@@ -832,7 +968,7 @@ void RendererViewport::viewport_remove_canvas(RID p_viewport, RID p_canvas) {
}
void RendererViewport::viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
ERR_FAIL_COND(!viewport->canvas_map.has(p_canvas));
@@ -840,7 +976,7 @@ void RendererViewport::viewport_set_canvas_transform(RID p_viewport, RID p_canva
}
void RendererViewport::viewport_set_transparent_background(RID p_viewport, bool p_enabled) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
RSG::storage->render_target_set_flag(viewport->render_target, RendererStorage::RENDER_TARGET_TRANSPARENT, p_enabled);
@@ -848,14 +984,14 @@ void RendererViewport::viewport_set_transparent_background(RID p_viewport, bool
}
void RendererViewport::viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
viewport->global_transform = p_transform;
}
void RendererViewport::viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
ERR_FAIL_COND(!viewport->canvas_map.has(p_canvas));
@@ -864,7 +1000,7 @@ void RendererViewport::viewport_set_canvas_stacking(RID p_viewport, RID p_canvas
}
void RendererViewport::viewport_set_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
viewport->shadow_atlas_size = p_size;
@@ -874,53 +1010,47 @@ void RendererViewport::viewport_set_shadow_atlas_size(RID p_viewport, int p_size
}
void RendererViewport::viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
RSG::scene->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv);
}
void RendererViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
if (viewport->msaa == p_msaa) {
return;
}
viewport->msaa = p_msaa;
- if (viewport->render_buffers.is_valid()) {
- RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa, viewport->screen_space_aa, viewport->use_debanding);
- }
+ _configure_3d_render_buffers(viewport);
}
void RendererViewport::viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(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_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, p_mode, viewport->use_debanding);
- }
+ _configure_3d_render_buffers(viewport);
}
void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_debanding) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
if (viewport->use_debanding == p_use_debanding) {
return;
}
viewport->use_debanding = p_use_debanding;
- if (viewport->render_buffers.is_valid()) {
- RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, p_use_debanding);
- }
+ _configure_3d_render_buffers(viewport);
}
void RendererViewport::viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
if (viewport->use_occlusion_culling == p_use_occlusion_culling) {
@@ -955,80 +1085,81 @@ void RendererViewport::viewport_set_occlusion_culling_build_quality(RS::Viewport
}
void RendererViewport::viewport_set_lod_threshold(RID p_viewport, float p_pixels) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
viewport->lod_threshold = p_pixels;
}
-int RendererViewport::viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info) {
+int RendererViewport::viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfoType p_type, RS::ViewportRenderInfo p_info) {
+ ERR_FAIL_INDEX_V(p_type, RS::VIEWPORT_RENDER_INFO_TYPE_MAX, -1);
ERR_FAIL_INDEX_V(p_info, RS::VIEWPORT_RENDER_INFO_MAX, -1);
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
if (!viewport) {
return 0; //there should be a lock here..
}
- return viewport->render_info[p_info];
+ return viewport->render_info.info[p_type][p_info];
}
void RendererViewport::viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
viewport->debug_draw = p_draw;
}
void RendererViewport::viewport_set_measure_render_time(RID p_viewport, bool p_enable) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
viewport->measure_render_time = p_enable;
}
float RendererViewport::viewport_get_measured_render_time_cpu(RID p_viewport) const {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND_V(!viewport, 0);
return double(viewport->time_cpu_end - viewport->time_cpu_begin) / 1000.0;
}
float RendererViewport::viewport_get_measured_render_time_gpu(RID p_viewport) const {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND_V(!viewport, 0);
return double((viewport->time_gpu_end - viewport->time_gpu_begin) / 1000) / 1000.0;
}
void RendererViewport::viewport_set_snap_2d_transforms_to_pixel(RID p_viewport, bool p_enabled) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
viewport->snap_2d_transforms_to_pixel = p_enabled;
}
void RendererViewport::viewport_set_snap_2d_vertices_to_pixel(RID p_viewport, bool p_enabled) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
viewport->snap_2d_vertices_to_pixel = p_enabled;
}
void RendererViewport::viewport_set_default_canvas_item_texture_filter(RID p_viewport, RS::CanvasItemTextureFilter p_filter) {
ERR_FAIL_COND_MSG(p_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, "Viewport does not accept DEFAULT as texture filter (it's the topmost choice already).)");
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
viewport->texture_filter = p_filter;
}
void RendererViewport::viewport_set_default_canvas_item_texture_repeat(RID p_viewport, RS::CanvasItemTextureRepeat p_repeat) {
ERR_FAIL_COND_MSG(p_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, "Viewport does not accept DEFAULT as texture repeat (it's the topmost choice already).)");
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
viewport->texture_repeat = p_repeat;
}
void RendererViewport::viewport_set_sdf_oversize_and_scale(RID p_viewport, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
RSG::storage->render_target_set_sdf_size_and_scale(viewport->render_target, p_size, p_scale);
@@ -1036,7 +1167,7 @@ void RendererViewport::viewport_set_sdf_oversize_and_scale(RID p_viewport, RS::V
bool RendererViewport::free(RID p_rid) {
if (viewport_owner.owns(p_rid)) {
- Viewport *viewport = viewport_owner.getornull(p_rid);
+ Viewport *viewport = viewport_owner.get_or_null(p_rid);
RSG::storage->free(viewport->render_target);
RSG::scene->free(viewport->shadow_atlas);
@@ -1056,7 +1187,6 @@ bool RendererViewport::free(RID p_rid) {
}
viewport_owner.free(p_rid);
- memdelete(viewport);
return true;
}
@@ -1070,7 +1200,7 @@ void RendererViewport::handle_timestamp(String p_timestamp, uint64_t p_cpu_time,
return;
}
- Viewport *viewport = viewport_owner.getornull(*vp);
+ Viewport *viewport = viewport_owner.get_or_null(*vp);
if (!viewport) {
return;
}
@@ -1090,9 +1220,19 @@ void RendererViewport::set_default_clear_color(const Color &p_color) {
RSG::storage->set_default_clear_color(p_color);
}
-//workaround for setting this on thread
-void RendererViewport::call_set_use_vsync(bool p_enable) {
- DisplayServer::get_singleton()->_set_use_vsync(p_enable);
+// Workaround for setting this on thread.
+void RendererViewport::call_set_vsync_mode(DisplayServer::VSyncMode p_mode, DisplayServer::WindowID p_window) {
+ DisplayServer::get_singleton()->window_set_vsync_mode(p_mode, p_window);
+}
+
+int RendererViewport::get_total_objects_drawn() const {
+ return total_objects_drawn;
+}
+int RendererViewport::get_total_vertices_drawn() const {
+ return total_vertices_drawn;
+}
+int RendererViewport::get_total_draw_calls_used() const {
+ return total_draw_calls_used;
}
RendererViewport::RendererViewport() {
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index 5c372e8c9a..5bb4dbbc6f 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -28,12 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef VISUALSERVERVIEWPORT_H
-#define VISUALSERVERVIEWPORT_H
+#ifndef RENDERER_VIEWPORT_H
+#define RENDERER_VIEWPORT_H
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
+#include "servers/rendering/renderer_scene.h"
#include "servers/rendering_server.h"
#include "servers/xr/xr_interface.h"
@@ -48,10 +49,16 @@ public:
bool use_xr; /* use xr interface to override camera positioning and projection matrices and control output */
+ Size2i internal_size;
Size2i size;
RID camera;
RID scenario;
+ RS::ViewportScaling3DMode scaling_3d_mode;
+ float scaling_3d_scale = 1.0;
+ float fsr_sharpness = 0.2f;
+ float fsr_mipmap_bias = 0.0f;
+ bool fsr_enabled;
RS::ViewportUpdateMode update_mode;
RID render_target;
RID render_target_texture;
@@ -68,9 +75,9 @@ public:
Rect2 viewport_to_screen_rect;
bool viewport_render_direct_to_screen;
- bool hide_scenario;
- bool hide_canvas;
- bool disable_environment;
+ bool disable_2d = false;
+ bool disable_environment = false;
+ bool disable_3d = false;
bool measure_render_time;
bool snap_2d_transforms_to_pixel;
@@ -92,7 +99,6 @@ public:
uint64_t last_pass = 0;
- int render_info[RS::VIEWPORT_RENDER_INFO_MAX];
RS::ViewportDebugDraw debug_draw;
RS::ViewportClearMode clear_mode;
@@ -133,11 +139,13 @@ public:
Map<RID, CanvasData> canvas_map;
+ RendererScene::RenderInfo render_info;
+
Viewport() {
update_mode = RS::VIEWPORT_UPDATE_WHEN_VISIBLE;
clear_mode = RS::VIEWPORT_CLEAR_ALWAYS;
transparent_bg = false;
- disable_environment = false;
+
viewport_to_screen = DisplayServer::INVALID_WINDOW_ID;
shadow_atlas_size = 0;
measure_render_time = false;
@@ -152,9 +160,6 @@ public:
snap_2d_transforms_to_pixel = false;
snap_2d_vertices_to_pixel = false;
- for (int i = 0; i < RS::VIEWPORT_RENDER_INFO_MAX; i++) {
- render_info[i] = 0;
- }
use_xr = false;
sdf_active = false;
@@ -164,13 +169,15 @@ public:
time_gpu_begin = 0;
time_gpu_end = 0;
}
+
+ uint32_t get_view_count();
};
HashMap<String, RID> timestamp_vp_map;
uint64_t draw_viewports_pass = 0;
- mutable RID_PtrOwner<Viewport, true> viewport_owner;
+ mutable RID_Owner<Viewport, true> viewport_owner;
struct ViewportSort {
_FORCE_INLINE_ bool operator()(const Viewport *p_left, const Viewport *p_right) const {
@@ -186,9 +193,14 @@ public:
Vector<Viewport *> active_viewports;
+ int total_objects_drawn = 0;
+ int total_vertices_drawn = 0;
+ int total_draw_calls_used = 0;
+
private:
- void _draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye);
- void _draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye = XRInterface::EYE_MONO);
+ void _configure_3d_render_buffers(Viewport *p_viewport);
+ void _draw_3d(Viewport *p_viewport);
+ void _draw_viewport(Viewport *p_viewport);
int occlusion_rays_per_thread = 512;
@@ -207,6 +219,12 @@ public:
void viewport_set_active(RID p_viewport, bool p_active);
void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport);
+
+ void viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode);
+ void viewport_set_scaling_3d_scale(RID p_viewport, float p_scaling_3d_scale);
+ void viewport_set_fsr_sharpness(RID p_viewport, float p_sharpness);
+ void viewport_set_fsr_mipmap_bias(RID p_viewport, float p_mipmap_bias);
+
void viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode);
void viewport_set_vflip(RID p_viewport, bool p_enable);
@@ -215,9 +233,9 @@ public:
RID viewport_get_texture(RID p_viewport) const;
RID viewport_get_occluder_debug_texture(RID p_viewport) const;
- void viewport_set_hide_scenario(RID p_viewport, bool p_hide);
- void viewport_set_hide_canvas(RID p_viewport, bool p_hide);
+ void viewport_set_disable_2d(RID p_viewport, bool p_disable);
void viewport_set_disable_environment(RID p_viewport, bool p_disable);
+ void viewport_set_disable_3d(RID p_viewport, bool p_disable);
void viewport_attach_camera(RID p_viewport, RID p_camera);
void viewport_set_scenario(RID p_viewport, RID p_scenario);
@@ -240,7 +258,7 @@ public:
void viewport_set_occlusion_culling_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality);
void viewport_set_lod_threshold(RID p_viewport, float p_pixels);
- virtual int viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info);
+ virtual int viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfoType p_type, 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);
@@ -262,11 +280,15 @@ public:
bool free(RID p_rid);
- //workaround for setting this on thread
- void call_set_use_vsync(bool p_enable);
+ int get_total_objects_drawn() const;
+ int get_total_vertices_drawn() const;
+ int get_total_draw_calls_used() const;
+
+ // Workaround for setting this on thread.
+ void call_set_vsync_mode(DisplayServer::VSyncMode p_mode, DisplayServer::WindowID p_window);
RendererViewport();
virtual ~RendererViewport() {}
};
-#endif // VISUALSERVERVIEWPORT_H
+#endif // RENDERER_VIEWPORT_H
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index e6ad001807..dcbc5f5c8e 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -38,18 +38,23 @@ RenderingDevice *RenderingDevice::get_singleton() {
return singleton;
}
-RenderingDevice::ShaderCompileFunction RenderingDevice::compile_function = nullptr;
+RenderingDevice::ShaderCompileToSPIRVFunction RenderingDevice::compile_to_spirv_function = nullptr;
RenderingDevice::ShaderCacheFunction RenderingDevice::cache_function = nullptr;
+RenderingDevice::ShaderSPIRVGetCacheKeyFunction RenderingDevice::get_spirv_cache_key_function = nullptr;
-void RenderingDevice::shader_set_compile_function(ShaderCompileFunction p_function) {
- compile_function = p_function;
+void RenderingDevice::shader_set_compile_to_spirv_function(ShaderCompileToSPIRVFunction p_function) {
+ compile_to_spirv_function = p_function;
}
-void RenderingDevice::shader_set_cache_function(ShaderCacheFunction p_function) {
+void RenderingDevice::shader_set_spirv_cache_function(ShaderCacheFunction p_function) {
cache_function = p_function;
}
-Vector<uint8_t> RenderingDevice::shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, bool p_allow_cache) {
+void RenderingDevice::shader_set_get_cache_key_function(ShaderSPIRVGetCacheKeyFunction p_function) {
+ get_spirv_cache_key_function = p_function;
+}
+
+Vector<uint8_t> RenderingDevice::shader_compile_spirv_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, bool p_allow_cache) {
if (p_allow_cache && cache_function) {
Vector<uint8_t> cache = cache_function(p_stage, p_source_code, p_language);
if (cache.size()) {
@@ -57,9 +62,22 @@ Vector<uint8_t> RenderingDevice::shader_compile_from_source(ShaderStage p_stage,
}
}
- ERR_FAIL_COND_V(!compile_function, Vector<uint8_t>());
+ ERR_FAIL_COND_V(!compile_to_spirv_function, Vector<uint8_t>());
+
+ return compile_to_spirv_function(p_stage, p_source_code, p_language, r_error, &device_capabilities);
+}
+
+String RenderingDevice::shader_get_spirv_cache_key() const {
+ if (get_spirv_cache_key_function) {
+ return get_spirv_cache_key_function(&device_capabilities);
+ }
+ return String();
+}
- return compile_function(p_stage, p_source_code, p_language, r_error, &device_capabilities);
+RID RenderingDevice::shader_create_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name) {
+ Vector<uint8_t> bytecode = shader_compile_binary_from_spirv(p_spirv, p_shader_name);
+ ERR_FAIL_COND_V(bytecode.size() == 0, RID());
+ return shader_create_from_bytecode(bytecode);
}
RID RenderingDevice::_texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data) {
@@ -86,7 +104,19 @@ RID RenderingDevice::_texture_create_shared_from_slice(const Ref<RDTextureView>
return texture_create_shared_from_slice(p_view->base, p_with_texture, p_layer, p_mipmap, p_slice_type);
}
-RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments) {
+RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments, uint32_t p_view_count) {
+ Vector<AttachmentFormat> attachments;
+ attachments.resize(p_attachments.size());
+
+ for (int i = 0; i < p_attachments.size(); i++) {
+ Ref<RDAttachmentFormat> af = p_attachments[i];
+ ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID);
+ attachments.write[i] = af->base;
+ }
+ return framebuffer_format_create(attachments, p_view_count);
+}
+
+RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create_multipass(const TypedArray<RDAttachmentFormat> &p_attachments, const TypedArray<RDFramebufferPass> &p_passes, uint32_t p_view_count) {
Vector<AttachmentFormat> attachments;
attachments.resize(p_attachments.size());
@@ -95,12 +125,31 @@ RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create
ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID);
attachments.write[i] = af->base;
}
- return framebuffer_format_create(attachments);
+
+ Vector<FramebufferPass> passes;
+ for (int i = 0; i < p_passes.size(); i++) {
+ Ref<RDFramebufferPass> pass = p_passes[i];
+ ERR_CONTINUE(pass.is_null());
+ passes.push_back(pass->base);
+ }
+
+ return framebuffer_format_create_multipass(attachments, passes, p_view_count);
}
-RID RenderingDevice::_framebuffer_create(const Array &p_textures, FramebufferFormatID p_format_check) {
+RID RenderingDevice::_framebuffer_create(const TypedArray<RID> &p_textures, FramebufferFormatID p_format_check, uint32_t p_view_count) {
Vector<RID> textures = Variant(p_textures);
- return framebuffer_create(textures, p_format_check);
+ return framebuffer_create(textures, p_format_check, p_view_count);
+}
+
+RID RenderingDevice::_framebuffer_create_multipass(const TypedArray<RID> &p_textures, const TypedArray<RDFramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) {
+ Vector<RID> textures = Variant(p_textures);
+ Vector<FramebufferPass> passes;
+ for (int i = 0; i < p_passes.size(); i++) {
+ Ref<RDFramebufferPass> pass = p_passes[i];
+ ERR_CONTINUE(pass.is_null());
+ passes.push_back(pass->base);
+ }
+ return framebuffer_create_multipass(textures, passes, p_format_check, p_view_count);
}
RID RenderingDevice::_sampler_create(const Ref<RDSamplerState> &p_state) {
@@ -127,40 +176,59 @@ RID RenderingDevice::_vertex_array_create(uint32_t p_vertex_count, VertexFormatI
return vertex_array_create(p_vertex_count, p_vertex_format, buffers);
}
-Ref<RDShaderBytecode> RenderingDevice::_shader_compile_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache) {
- ERR_FAIL_COND_V(p_source.is_null(), Ref<RDShaderBytecode>());
+Ref<RDShaderSPIRV> RenderingDevice::_shader_compile_spirv_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache) {
+ ERR_FAIL_COND_V(p_source.is_null(), Ref<RDShaderSPIRV>());
- Ref<RDShaderBytecode> bytecode;
- bytecode.instance();
+ Ref<RDShaderSPIRV> bytecode;
+ bytecode.instantiate();
for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
String error;
ShaderStage stage = ShaderStage(i);
- Vector<uint8_t> spirv = shader_compile_from_source(stage, p_source->get_stage_source(stage), p_source->get_language(), &error, p_allow_cache);
+ Vector<uint8_t> spirv = shader_compile_spirv_from_source(stage, p_source->get_stage_source(stage), p_source->get_language(), &error, p_allow_cache);
bytecode->set_stage_bytecode(stage, spirv);
bytecode->set_stage_compile_error(stage, error);
}
return bytecode;
}
-RID RenderingDevice::shader_create_from_bytecode(const Ref<RDShaderBytecode> &p_bytecode) {
- ERR_FAIL_COND_V(p_bytecode.is_null(), RID());
+Vector<uint8_t> RenderingDevice::_shader_compile_binary_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name) {
+ ERR_FAIL_COND_V(p_spirv.is_null(), Vector<uint8_t>());
- Vector<ShaderStageData> stage_data;
+ Vector<ShaderStageSPIRVData> stage_data;
for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
ShaderStage stage = ShaderStage(i);
- ShaderStageData sd;
+ ShaderStageSPIRVData sd;
sd.shader_stage = stage;
- String error = p_bytecode->get_stage_compile_error(stage);
- ERR_FAIL_COND_V_MSG(error != String(), RID(), "Can't create a shader from an errored bytecode. Check errors in source bytecode.");
- sd.spir_v = p_bytecode->get_stage_bytecode(stage);
+ String error = p_spirv->get_stage_compile_error(stage);
+ ERR_FAIL_COND_V_MSG(error != String(), Vector<uint8_t>(), "Can't create a shader from an errored bytecode. Check errors in source bytecode.");
+ sd.spir_v = p_spirv->get_stage_bytecode(stage);
if (sd.spir_v.is_empty()) {
continue;
}
stage_data.push_back(sd);
}
- return shader_create(stage_data);
+ return shader_compile_binary_from_spirv(stage_data, p_shader_name);
+}
+
+RID RenderingDevice::_shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name) {
+ ERR_FAIL_COND_V(p_spirv.is_null(), RID());
+
+ Vector<ShaderStageSPIRVData> stage_data;
+ for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
+ ShaderStage stage = ShaderStage(i);
+ ShaderStageSPIRVData sd;
+ sd.shader_stage = stage;
+ String error = p_spirv->get_stage_compile_error(stage);
+ ERR_FAIL_COND_V_MSG(error != String(), RID(), "Can't create a shader from an errored bytecode. Check errors in source bytecode.");
+ sd.spir_v = p_spirv->get_stage_bytecode(stage);
+ if (sd.spir_v.is_empty()) {
+ continue;
+ }
+ stage_data.push_back(sd);
+ }
+ return shader_create_from_spirv(stage_data);
}
RID RenderingDevice::_uniform_set_create(const Array &p_uniforms, RID p_shader, uint32_t p_shader_set) {
@@ -178,7 +246,36 @@ Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t
return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier);
}
-RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags) {
+static Vector<RenderingDevice::PipelineSpecializationConstant> _get_spec_constants(const TypedArray<RDPipelineSpecializationConstant> &p_constants) {
+ Vector<RenderingDevice::PipelineSpecializationConstant> ret;
+ ret.resize(p_constants.size());
+ for (int i = 0; i < p_constants.size(); i++) {
+ Ref<RDPipelineSpecializationConstant> c = p_constants[i];
+ ERR_CONTINUE(c.is_null());
+ RenderingDevice::PipelineSpecializationConstant &sc = ret.write[i];
+ Variant value = c->get_value();
+ switch (value.get_type()) {
+ case Variant::BOOL: {
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
+ sc.bool_value = value;
+ } break;
+ case Variant::INT: {
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
+ sc.int_value = value;
+ } break;
+ case Variant::FLOAT: {
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;
+ sc.float_value = value;
+ } break;
+ default: {
+ }
+ }
+
+ sc.constant_id = c->get_constant_id();
+ }
+ return ret;
+}
+RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants) {
PipelineRasterizationState rasterization_state;
if (p_rasterization_state.is_valid()) {
rasterization_state = p_rasterization_state->base;
@@ -209,7 +306,11 @@ RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p
}
}
- return render_pipeline_create(p_shader, p_framebuffer_format, p_vertex_format, p_render_primitive, rasterization_state, multisample_state, depth_stencil_state, color_blend_state, p_dynamic_state_flags);
+ return render_pipeline_create(p_shader, p_framebuffer_format, p_vertex_format, p_render_primitive, rasterization_state, multisample_state, depth_stencil_state, color_blend_state, p_dynamic_state_flags, p_for_render_pass, _get_spec_constants(p_specialization_constants));
+}
+
+RID RenderingDevice::_compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants = TypedArray<RDPipelineSpecializationConstant>()) {
+ return compute_pipeline_create(p_shader, _get_spec_constants(p_specialization_constants));
}
Vector<int64_t> RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures) {
@@ -230,6 +331,22 @@ Vector<int64_t> RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint3
return split_ids;
}
+Vector<int64_t> RenderingDevice::_draw_list_switch_to_next_pass_split(uint32_t p_splits) {
+ Vector<DrawListID> splits;
+ splits.resize(p_splits);
+
+ Error err = draw_list_switch_to_next_pass_split(p_splits, splits.ptrw());
+ ERR_FAIL_COND_V(err != OK, Vector<int64_t>());
+
+ Vector<int64_t> split_ids;
+ split_ids.resize(splits.size());
+ for (int i = 0; i < splits.size(); i++) {
+ split_ids.write[i] = splits[i];
+ }
+
+ return split_ids;
+}
+
void RenderingDevice::_draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) {
ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size);
draw_list_set_push_constant(p_list, p_data.ptr(), p_data_size);
@@ -257,10 +374,12 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::texture_clear, DEFVAL(BARRIER_MASK_ALL));
ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::texture_resolve_multisample, DEFVAL(BARRIER_MASK_ALL));
- ClassDB::bind_method(D_METHOD("framebuffer_format_create", "attachments"), &RenderingDevice::_framebuffer_format_create);
+ ClassDB::bind_method(D_METHOD("framebuffer_format_create", "attachments", "view_count"), &RenderingDevice::_framebuffer_format_create, DEFVAL(1));
+ ClassDB::bind_method(D_METHOD("framebuffer_format_create_multipass", "attachments", "passes", "view_count"), &RenderingDevice::_framebuffer_format_create_multipass, DEFVAL(1));
ClassDB::bind_method(D_METHOD("framebuffer_format_create_empty", "samples"), &RenderingDevice::framebuffer_format_create_empty, DEFVAL(TEXTURE_SAMPLES_1));
- ClassDB::bind_method(D_METHOD("framebuffer_format_get_texture_samples", "format"), &RenderingDevice::framebuffer_format_get_texture_samples);
- ClassDB::bind_method(D_METHOD("framebuffer_create", "textures", "validate_with_format"), &RenderingDevice::_framebuffer_create, DEFVAL(INVALID_FORMAT_ID));
+ ClassDB::bind_method(D_METHOD("framebuffer_format_get_texture_samples", "format", "render_pass"), &RenderingDevice::framebuffer_format_get_texture_samples, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("framebuffer_create", "textures", "validate_with_format", "view_count"), &RenderingDevice::_framebuffer_create, DEFVAL(INVALID_FORMAT_ID), DEFVAL(1));
+ ClassDB::bind_method(D_METHOD("framebuffer_create_multipass", "textures", "passes", "validate_with_format", "view_count"), &RenderingDevice::_framebuffer_create_multipass, DEFVAL(INVALID_FORMAT_ID), DEFVAL(1));
ClassDB::bind_method(D_METHOD("framebuffer_create_empty", "size", "samples", "validate_with_format"), &RenderingDevice::framebuffer_create_empty, DEFVAL(TEXTURE_SAMPLES_1), DEFVAL(INVALID_FORMAT_ID));
ClassDB::bind_method(D_METHOD("framebuffer_get_format", "framebuffer"), &RenderingDevice::framebuffer_get_format);
@@ -272,8 +391,10 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("index_buffer_create", "size_indices", "format", "data", "use_restart_indices"), &RenderingDevice::index_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("index_array_create", "index_buffer", "index_offset", "index_count"), &RenderingDevice::index_array_create);
- ClassDB::bind_method(D_METHOD("shader_compile_from_source", "shader_source", "allow_cache"), &RenderingDevice::_shader_compile_from_source, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("shader_create", "shader_data"), &RenderingDevice::shader_create_from_bytecode);
+ ClassDB::bind_method(D_METHOD("shader_compile_spirv_from_source", "shader_source", "allow_cache"), &RenderingDevice::_shader_compile_spirv_from_source, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("shader_compile_binary_from_spirv", "spirv_data", "name"), &RenderingDevice::_shader_compile_binary_from_spirv, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("shader_create_from_spirv", "spirv_data", "name"), &RenderingDevice::_shader_create_from_spirv, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("shader_create_from_bytecode", "binary_data"), &RenderingDevice::shader_create_from_bytecode);
ClassDB::bind_method(D_METHOD("shader_get_vertex_input_attribute_mask", "shader"), &RenderingDevice::shader_get_vertex_input_attribute_mask);
ClassDB::bind_method(D_METHOD("uniform_buffer_create", "size_bytes", "data"), &RenderingDevice::uniform_buffer_create, DEFVAL(Vector<uint8_t>()));
@@ -287,10 +408,10 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::buffer_clear, DEFVAL(BARRIER_MASK_ALL));
ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer"), &RenderingDevice::buffer_get_data);
- ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags"), &RenderingDevice::_render_pipeline_create, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags", "for_render_pass", "specialization_constants"), &RenderingDevice::_render_pipeline_create, DEFVAL(0), DEFVAL(0), DEFVAL(TypedArray<RDPipelineSpecializationConstant>()));
ClassDB::bind_method(D_METHOD("render_pipeline_is_valid", "render_pipeline"), &RenderingDevice::render_pipeline_is_valid);
- ClassDB::bind_method(D_METHOD("compute_pipeline_create", "shader"), &RenderingDevice::compute_pipeline_create);
+ ClassDB::bind_method(D_METHOD("compute_pipeline_create", "shader", "specialization_constants"), &RenderingDevice::_compute_pipeline_create, DEFVAL(TypedArray<RDPipelineSpecializationConstant>()));
ClassDB::bind_method(D_METHOD("compute_pipeline_is_valid", "compute_pieline"), &RenderingDevice::compute_pipeline_is_valid);
ClassDB::bind_method(D_METHOD("screen_get_width", "screen"), &RenderingDevice::screen_get_width, DEFVAL(DisplayServer::MAIN_WINDOW_ID));
@@ -299,8 +420,8 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_list_begin_for_screen", "screen", "clear_color"), &RenderingDevice::draw_list_begin_for_screen, DEFVAL(DisplayServer::MAIN_WINDOW_ID), DEFVAL(Color()));
- ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::draw_list_begin, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2i()), DEFVAL(TypedArray<RID>()));
- ClassDB::bind_method(D_METHOD("draw_list_begin_split", "framebuffer", "splits", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_split, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2i()), DEFVAL(TypedArray<RID>()));
+ ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::draw_list_begin, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
+ ClassDB::bind_method(D_METHOD("draw_list_begin_split", "framebuffer", "splits", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_split, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
ClassDB::bind_method(D_METHOD("draw_list_bind_render_pipeline", "draw_list", "render_pipeline"), &RenderingDevice::draw_list_bind_render_pipeline);
ClassDB::bind_method(D_METHOD("draw_list_bind_uniform_set", "draw_list", "uniform_set", "set_index"), &RenderingDevice::draw_list_bind_uniform_set);
@@ -310,9 +431,12 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_list_draw", "draw_list", "use_indices", "instances", "procedural_vertex_count"), &RenderingDevice::draw_list_draw, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("draw_list_enable_scissor", "draw_list", "rect"), &RenderingDevice::draw_list_enable_scissor, DEFVAL(Rect2i()));
+ ClassDB::bind_method(D_METHOD("draw_list_enable_scissor", "draw_list", "rect"), &RenderingDevice::draw_list_enable_scissor, DEFVAL(Rect2()));
ClassDB::bind_method(D_METHOD("draw_list_disable_scissor", "draw_list"), &RenderingDevice::draw_list_disable_scissor);
+ ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass"), &RenderingDevice::draw_list_switch_to_next_pass);
+ ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass_split", "splits"), &RenderingDevice::_draw_list_switch_to_next_pass_split);
+
ClassDB::bind_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::draw_list_end, DEFVAL(BARRIER_MASK_ALL));
ClassDB::bind_method(D_METHOD("compute_list_begin", "allow_draw_overlap"), &RenderingDevice::compute_list_begin, DEFVAL(false));
@@ -352,12 +476,30 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_device_name"), &RenderingDevice::get_device_name);
ClassDB::bind_method(D_METHOD("get_device_pipeline_cache_uuid"), &RenderingDevice::get_device_pipeline_cache_uuid);
+ ClassDB::bind_method(D_METHOD("get_memory_usage", "type"), &RenderingDevice::get_memory_usage);
+
+ ClassDB::bind_method(D_METHOD("get_driver_resource", "resource", "rid", "index"), &RenderingDevice::get_driver_resource);
+
BIND_CONSTANT(BARRIER_MASK_RASTER);
BIND_CONSTANT(BARRIER_MASK_COMPUTE);
BIND_CONSTANT(BARRIER_MASK_TRANSFER);
BIND_CONSTANT(BARRIER_MASK_ALL);
BIND_CONSTANT(BARRIER_MASK_NO_BARRIER);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_DEVICE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_INSTANCE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_QUEUE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE_VIEW);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_SAMPLER);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_BUFFER);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE);
+
BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4_UNORM_PACK8);
BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4B4A4_UNORM_PACK16);
BIND_ENUM_CONSTANT(DATA_FORMAT_B4G4R4A4_UNORM_PACK16);
@@ -613,7 +755,7 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(TEXTURE_USAGE_CAN_UPDATE_BIT);
BIND_ENUM_CONSTANT(TEXTURE_USAGE_CAN_COPY_FROM_BIT);
BIND_ENUM_CONSTANT(TEXTURE_USAGE_CAN_COPY_TO_BIT);
- BIND_ENUM_CONSTANT(TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT);
+ BIND_ENUM_CONSTANT(TEXTURE_USAGE_INPUT_ATTACHMENT_BIT);
BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_IDENTITY);
BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_ZERO);
@@ -787,6 +929,10 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(SHADER_LANGUAGE_GLSL);
BIND_ENUM_CONSTANT(SHADER_LANGUAGE_HLSL);
+ BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL);
+ BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT);
+ BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT);
+
BIND_ENUM_CONSTANT(LIMIT_MAX_BOUND_UNIFORM_SETS);
BIND_ENUM_CONSTANT(LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS);
BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURES_PER_UNIFORM_SET);
@@ -823,6 +969,10 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y);
BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z);
+ BIND_ENUM_CONSTANT(MEMORY_TEXTURES);
+ BIND_ENUM_CONSTANT(MEMORY_BUFFERS);
+ BIND_ENUM_CONSTANT(MEMORY_TOTAL);
+
BIND_CONSTANT(INVALID_ID);
BIND_CONSTANT(INVALID_FORMAT_ID);
}
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index d86c44a206..563a80c12c 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -41,12 +41,14 @@ class RDAttachmentFormat;
class RDSamplerState;
class RDVertexAttribute;
class RDShaderSource;
-class RDShaderBytecode;
+class RDShaderSPIRV;
class RDUniforms;
class RDPipelineRasterizationState;
class RDPipelineMultisampleState;
class RDPipelineDepthStencilState;
class RDPipelineColorBlendState;
+class RDFramebufferPass;
+class RDPipelineSpecializationConstant;
class RenderingDevice : public Object {
GDCLASS(RenderingDevice, Object)
@@ -58,6 +60,23 @@ public:
DEVICE_DIRECTX
};
+ enum DriverResource {
+ DRIVER_RESOURCE_VULKAN_DEVICE = 0,
+ DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE,
+ DRIVER_RESOURCE_VULKAN_INSTANCE,
+ DRIVER_RESOURCE_VULKAN_QUEUE,
+ DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX,
+ DRIVER_RESOURCE_VULKAN_IMAGE,
+ DRIVER_RESOURCE_VULKAN_IMAGE_VIEW,
+ DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT,
+ DRIVER_RESOURCE_VULKAN_SAMPLER,
+ DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET,
+ DRIVER_RESOURCE_VULKAN_BUFFER,
+ DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE,
+ DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE,
+ //next driver continue enum from 1000 to keep order
+ };
+
enum ShaderStage {
SHADER_STAGE_VERTEX,
SHADER_STAGE_FRAGMENT,
@@ -101,14 +120,17 @@ public:
// features
bool supports_multiview = false; // If true this device supports multiview options
+ bool supports_fsr_half_float = false; // If true this device supports FSR scaling 3D in half float mode, otherwise use the fallback mode
};
- typedef Vector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const Capabilities *p_capabilities);
+ typedef String (*ShaderSPIRVGetCacheKeyFunction)(const Capabilities *p_capabilities);
+ typedef Vector<uint8_t> (*ShaderCompileToSPIRVFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const Capabilities *p_capabilities);
typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language);
private:
- static ShaderCompileFunction compile_function;
+ static ShaderCompileToSPIRVFunction compile_to_spirv_function;
static ShaderCacheFunction cache_function;
+ static ShaderSPIRVGetCacheKeyFunction get_spirv_cache_key_function;
static RenderingDevice *singleton;
@@ -418,7 +440,7 @@ public:
TEXTURE_USAGE_CAN_UPDATE_BIT = (1 << 6),
TEXTURE_USAGE_CAN_COPY_FROM_BIT = (1 << 7),
TEXTURE_USAGE_CAN_COPY_TO_BIT = (1 << 8),
- TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT = (1 << 9),
+ TEXTURE_USAGE_INPUT_ATTACHMENT_BIT = (1 << 9),
};
enum TextureSwizzle {
@@ -491,6 +513,7 @@ public:
virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const = 0;
virtual bool texture_is_shared(RID p_texture) = 0;
virtual bool texture_is_valid(RID p_texture) = 0;
+ virtual Size2i texture_size(RID p_texture) = 0;
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, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 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, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0;
@@ -514,11 +537,24 @@ public:
typedef int64_t FramebufferFormatID;
// This ID is warranted to be unique for the same formats, does not need to be freed
- virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format) = 0;
+ virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count = 1) = 0;
+ struct FramebufferPass {
+ enum {
+ ATTACHMENT_UNUSED = -1
+ };
+ Vector<int32_t> color_attachments;
+ Vector<int32_t> input_attachments;
+ Vector<int32_t> resolve_attachments;
+ Vector<int32_t> preserve_attachments;
+ int32_t depth_attachment = ATTACHMENT_UNUSED;
+ };
+
+ virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1) = 0;
virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1) = 0;
- virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format) = 0;
+ virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass = 0) = 0;
- virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID) = 0;
+ virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1) = 0;
+ virtual RID framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1) = 0;
virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID) = 0;
virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer) = 0;
@@ -634,22 +670,28 @@ public:
const Capabilities *get_device_capabilities() const { return &device_capabilities; };
- virtual Vector<uint8_t> shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language = SHADER_LANGUAGE_GLSL, String *r_error = nullptr, bool p_allow_cache = true);
+ virtual Vector<uint8_t> shader_compile_spirv_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language = SHADER_LANGUAGE_GLSL, String *r_error = nullptr, bool p_allow_cache = true);
+ virtual String shader_get_spirv_cache_key() const;
- static void shader_set_compile_function(ShaderCompileFunction p_function);
- static void shader_set_cache_function(ShaderCacheFunction p_function);
+ static void shader_set_compile_to_spirv_function(ShaderCompileToSPIRVFunction p_function);
+ static void shader_set_spirv_cache_function(ShaderCacheFunction p_function);
+ static void shader_set_get_cache_key_function(ShaderSPIRVGetCacheKeyFunction p_function);
- struct ShaderStageData {
+ struct ShaderStageSPIRVData {
ShaderStage shader_stage;
Vector<uint8_t> spir_v;
- ShaderStageData() {
+ ShaderStageSPIRVData() {
shader_stage = SHADER_STAGE_VERTEX;
}
};
- RID shader_create_from_bytecode(const Ref<RDShaderBytecode> &p_bytecode);
- virtual RID shader_create(const Vector<ShaderStageData> &p_stages) = 0;
+ virtual String shader_get_binary_cache_key() const = 0;
+ virtual Vector<uint8_t> shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name = "") = 0;
+
+ virtual RID shader_create_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name = "");
+ virtual RID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary) = 0;
+
virtual uint32_t shader_get_vertex_input_attribute_mask(RID p_shader) = 0;
/******************/
@@ -697,11 +739,39 @@ public:
virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) = 0;
virtual bool uniform_set_is_valid(RID p_uniform_set) = 0;
+ typedef void (*UniformSetInvalidatedCallback)(const RID &, void *);
+ virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata) = 0;
virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0;
virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0;
virtual Vector<uint8_t> buffer_get_data(RID p_buffer) = 0; //this causes stall, only use to retrieve large buffers for saving
+ /******************************************/
+ /**** PIPELINE SPECIALIZATION CONSTANT ****/
+ /******************************************/
+
+ enum PipelineSpecializationConstantType {
+ PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL,
+ PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT,
+ PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT,
+ };
+
+ struct PipelineSpecializationConstant {
+ PipelineSpecializationConstantType type;
+ uint32_t constant_id;
+ union {
+ uint32_t int_value;
+ float float_value;
+ bool bool_value;
+ };
+
+ PipelineSpecializationConstant() {
+ type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
+ constant_id = 0;
+ int_value = 0;
+ }
+ };
+
/*************************/
/**** RENDER PIPELINE ****/
/*************************/
@@ -958,13 +1028,13 @@ public:
};
virtual bool render_pipeline_is_valid(RID p_pipeline) = 0;
- virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0) = 0;
+ virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()) = 0;
/**************************/
/**** COMPUTE PIPELINE ****/
/**************************/
- virtual RID compute_pipeline_create(RID p_shader) = 0;
+ virtual RID compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()) = 0;
virtual bool compute_pipeline_is_valid(RID p_pipeline) = 0;
/****************/
@@ -982,7 +1052,7 @@ public:
enum InitialAction {
INITIAL_ACTION_CLEAR, //start rendering and clear the whole framebuffer (region or not) (supply params)
INITIAL_ACTION_CLEAR_REGION, //start rendering and clear the framebuffer in the specified region (supply params)
- INITIAL_ACTION_CLEAR_REGION_CONTINUE, //countinue rendering and clear the framebuffer in the specified region (supply params)
+ INITIAL_ACTION_CLEAR_REGION_CONTINUE, //continue rendering and clear the framebuffer in the specified region (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)
@@ -1014,6 +1084,10 @@ public:
virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) = 0;
virtual void draw_list_disable_scissor(DrawListID p_list) = 0;
+ virtual uint32_t draw_list_get_current_pass() = 0;
+ virtual DrawListID draw_list_switch_to_next_pass() = 0;
+ virtual Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) = 0;
+
virtual void draw_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0;
/***********************/
@@ -1107,7 +1181,13 @@ public:
virtual void submit() = 0;
virtual void sync() = 0;
- virtual uint64_t get_memory_usage() const = 0;
+ enum MemoryType {
+ MEMORY_TEXTURES,
+ MEMORY_BUFFERS,
+ MEMORY_TOTAL
+ };
+
+ virtual uint64_t get_memory_usage(MemoryType p_type) const = 0;
virtual RenderingDevice *create_local_device() = 0;
@@ -1121,6 +1201,8 @@ public:
virtual String get_device_name() const = 0;
virtual String get_device_pipeline_cache_uuid() const = 0;
+ virtual uint64_t get_driver_resource(DriverResource p_resource, RID p_rid = RID(), uint64_t p_index = 0) = 0;
+
static RenderingDevice *get_singleton();
RenderingDevice();
@@ -1130,25 +1212,32 @@ protected:
RID _texture_create_shared(const Ref<RDTextureView> &p_view, RID p_with_texture);
RID _texture_create_shared_from_slice(const Ref<RDTextureView> &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type = TEXTURE_SLICE_2D);
- FramebufferFormatID _framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments);
- RID _framebuffer_create(const Array &p_textures, FramebufferFormatID p_format_check = INVALID_ID);
+ FramebufferFormatID _framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments, uint32_t p_view_count);
+ FramebufferFormatID _framebuffer_format_create_multipass(const TypedArray<RDAttachmentFormat> &p_attachments, const TypedArray<RDFramebufferPass> &p_passes, uint32_t p_view_count);
+ RID _framebuffer_create(const TypedArray<RID> &p_textures, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
+ RID _framebuffer_create_multipass(const TypedArray<RID> &p_textures, const TypedArray<RDFramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
RID _sampler_create(const Ref<RDSamplerState> &p_state);
VertexFormatID _vertex_format_create(const TypedArray<RDVertexAttribute> &p_vertex_formats);
RID _vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const TypedArray<RID> &p_src_buffers);
- Ref<RDShaderBytecode> _shader_compile_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache = true);
+ Ref<RDShaderSPIRV> _shader_compile_spirv_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache = true);
+ Vector<uint8_t> _shader_compile_binary_from_spirv(const Ref<RDShaderSPIRV> &p_bytecode, const String &p_shader_name = "");
+ RID _shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name = "");
RID _uniform_set_create(const Array &p_uniforms, RID p_shader, uint32_t p_shader_set);
Error _buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL);
- RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags = 0);
+ RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants);
+ RID _compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants);
Vector<int64_t> _draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const TypedArray<RID> &p_storage_textures = TypedArray<RID>());
void _draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size);
void _compute_list_set_push_constant(ComputeListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size);
+ Vector<int64_t> _draw_list_switch_to_next_pass_split(uint32_t p_splits);
};
+VARIANT_ENUM_CAST(RenderingDevice::DriverResource)
VARIANT_ENUM_CAST(RenderingDevice::ShaderStage)
VARIANT_ENUM_CAST(RenderingDevice::ShaderLanguage)
VARIANT_ENUM_CAST(RenderingDevice::CompareOperator)
@@ -1173,9 +1262,11 @@ VARIANT_ENUM_CAST(RenderingDevice::LogicOperation)
VARIANT_ENUM_CAST(RenderingDevice::BlendFactor)
VARIANT_ENUM_CAST(RenderingDevice::BlendOperation)
VARIANT_ENUM_CAST(RenderingDevice::PipelineDynamicStateFlags)
+VARIANT_ENUM_CAST(RenderingDevice::PipelineSpecializationConstantType)
VARIANT_ENUM_CAST(RenderingDevice::InitialAction)
VARIANT_ENUM_CAST(RenderingDevice::FinalAction)
VARIANT_ENUM_CAST(RenderingDevice::Limit)
+VARIANT_ENUM_CAST(RenderingDevice::MemoryType)
typedef RenderingDevice RD;
diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp
index 2f11360364..a21f28989b 100644
--- a/servers/rendering/rendering_device_binds.cpp
+++ b/servers/rendering/rendering_device_binds.cpp
@@ -156,7 +156,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String
}
Ref<RDShaderFile> shader_file;
- shader_file.instance();
+ shader_file.instantiate();
if (base_error == "") {
if (stage_found[RD::SHADER_STAGE_COMPUTE] && stages_found > 1) {
@@ -171,18 +171,18 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String
/* STEP 2, Compile the versions, add to shader file */
- for (Map<StringName, String>::Element *E = version_texts.front(); E; E = E->next()) {
- Ref<RDShaderBytecode> bytecode;
- bytecode.instance();
+ for (const KeyValue<StringName, String> &E : version_texts) {
+ Ref<RDShaderSPIRV> bytecode;
+ bytecode.instantiate();
for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
String code = stage_code[i];
if (code == String()) {
continue;
}
- code = code.replace("VERSION_DEFINES", E->get());
+ code = code.replace("VERSION_DEFINES", E.value);
String error;
- Vector<uint8_t> spirv = RenderingDevice::get_singleton()->shader_compile_from_source(RD::ShaderStage(i), code, RD::SHADER_LANGUAGE_GLSL, &error, false);
+ Vector<uint8_t> spirv = RenderingDevice::get_singleton()->shader_compile_spirv_from_source(RD::ShaderStage(i), code, RD::SHADER_LANGUAGE_GLSL, &error, false);
bytecode->set_stage_bytecode(RD::ShaderStage(i), spirv);
if (error != "") {
error += String() + "\n\nStage '" + stage_str[i] + "' source code: \n\n";
@@ -195,7 +195,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String
bytecode->set_stage_compile_error(RD::ShaderStage(i), error);
}
- set_bytecode(bytecode, E->key());
+ set_bytecode(bytecode, E.key);
}
return errors_found ? ERR_PARSE_ERROR : OK;
diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h
index e43c3669b5..2cf7821668 100644
--- a/servers/rendering/rendering_device_binds.h
+++ b/servers/rendering/rendering_device_binds.h
@@ -51,8 +51,8 @@
ClassDB::bind_method(D_METHOD("get_" _MKSTR(m_sub) "_" _MKSTR(m_member)), &m_class::get_##m_sub##_##m_member); \
ADD_PROPERTY(PropertyInfo(m_variant_type, _MKSTR(m_sub) "_" _MKSTR(m_member)), "set_" _MKSTR(m_sub) "_" _MKSTR(m_member), "get_" _MKSTR(m_sub) "_" _MKSTR(m_member))
-class RDTextureFormat : public Reference {
- GDCLASS(RDTextureFormat, Reference)
+class RDTextureFormat : public RefCounted {
+ GDCLASS(RDTextureFormat, RefCounted)
friend class RenderingDevice;
RD::TextureFormat base;
@@ -87,8 +87,8 @@ protected:
}
};
-class RDTextureView : public Reference {
- GDCLASS(RDTextureView, Reference)
+class RDTextureView : public RefCounted {
+ GDCLASS(RDTextureView, RefCounted)
friend class RenderingDevice;
@@ -110,8 +110,8 @@ protected:
}
};
-class RDAttachmentFormat : public Reference {
- GDCLASS(RDAttachmentFormat, Reference)
+class RDAttachmentFormat : public RefCounted {
+ GDCLASS(RDAttachmentFormat, RefCounted)
friend class RenderingDevice;
RD::AttachmentFormat base;
@@ -128,8 +128,36 @@ protected:
}
};
-class RDSamplerState : public Reference {
- GDCLASS(RDSamplerState, Reference)
+class RDFramebufferPass : public RefCounted {
+ GDCLASS(RDFramebufferPass, RefCounted)
+ friend class RenderingDevice;
+
+ RD::FramebufferPass base;
+
+public:
+ RD_SETGET(PackedInt32Array, color_attachments)
+ RD_SETGET(PackedInt32Array, input_attachments)
+ RD_SETGET(PackedInt32Array, resolve_attachments)
+ RD_SETGET(PackedInt32Array, preserve_attachments)
+ RD_SETGET(int32_t, depth_attachment)
+protected:
+ enum {
+ ATTACHMENT_UNUSED = -1
+ };
+
+ static void _bind_methods() {
+ RD_BIND(Variant::PACKED_INT32_ARRAY, RDFramebufferPass, color_attachments);
+ RD_BIND(Variant::PACKED_INT32_ARRAY, RDFramebufferPass, input_attachments);
+ RD_BIND(Variant::PACKED_INT32_ARRAY, RDFramebufferPass, resolve_attachments);
+ RD_BIND(Variant::PACKED_INT32_ARRAY, RDFramebufferPass, preserve_attachments);
+ RD_BIND(Variant::INT, RDFramebufferPass, depth_attachment);
+
+ BIND_CONSTANT(ATTACHMENT_UNUSED);
+ }
+};
+
+class RDSamplerState : public RefCounted {
+ GDCLASS(RDSamplerState, RefCounted)
friend class RenderingDevice;
RD::SamplerState base;
@@ -171,8 +199,8 @@ protected:
}
};
-class RDVertexAttribute : public Reference {
- GDCLASS(RDVertexAttribute, Reference)
+class RDVertexAttribute : public RefCounted {
+ GDCLASS(RDVertexAttribute, RefCounted)
friend class RenderingDevice;
RD::VertexAttribute base;
@@ -192,8 +220,8 @@ protected:
RD_BIND(Variant::INT, RDVertexAttribute, frequency);
}
};
-class RDShaderSource : public Reference {
- GDCLASS(RDShaderSource, Reference)
+class RDShaderSource : public RefCounted {
+ GDCLASS(RDShaderSource, RefCounted)
String source[RD::SHADER_STAGE_MAX];
RD::ShaderLanguage language = RD::SHADER_LANGUAGE_GLSL;
@@ -235,8 +263,8 @@ protected:
}
};
-class RDShaderBytecode : public Resource {
- GDCLASS(RDShaderBytecode, Resource)
+class RDShaderSPIRV : public Resource {
+ GDCLASS(RDShaderSPIRV, Resource)
Vector<uint8_t> bytecode[RD::SHADER_STAGE_MAX];
String compile_error[RD::SHADER_STAGE_MAX];
@@ -252,6 +280,19 @@ public:
return bytecode[p_stage];
}
+ Vector<RD::ShaderStageSPIRVData> get_stages() const {
+ Vector<RD::ShaderStageSPIRVData> stages;
+ for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
+ if (bytecode[i].size()) {
+ RD::ShaderStageSPIRVData stage;
+ stage.shader_stage = RD::ShaderStage(i);
+ stage.spir_v = bytecode[i];
+ stages.push_back(stage);
+ }
+ }
+ return stages;
+ }
+
void set_stage_compile_error(RD::ShaderStage p_stage, const String &p_compile_error) {
ERR_FAIL_INDEX(p_stage, RD::SHADER_STAGE_MAX);
compile_error[p_stage] = p_compile_error;
@@ -264,11 +305,11 @@ public:
protected:
static void _bind_methods() {
- ClassDB::bind_method(D_METHOD("set_stage_bytecode", "stage", "bytecode"), &RDShaderBytecode::set_stage_bytecode);
- ClassDB::bind_method(D_METHOD("get_stage_bytecode", "stage"), &RDShaderBytecode::get_stage_bytecode);
+ ClassDB::bind_method(D_METHOD("set_stage_bytecode", "stage", "bytecode"), &RDShaderSPIRV::set_stage_bytecode);
+ ClassDB::bind_method(D_METHOD("get_stage_bytecode", "stage"), &RDShaderSPIRV::get_stage_bytecode);
- ClassDB::bind_method(D_METHOD("set_stage_compile_error", "stage", "compile_error"), &RDShaderBytecode::set_stage_compile_error);
- ClassDB::bind_method(D_METHOD("get_stage_compile_error", "stage"), &RDShaderBytecode::get_stage_compile_error);
+ ClassDB::bind_method(D_METHOD("set_stage_compile_error", "stage", "compile_error"), &RDShaderSPIRV::set_stage_compile_error);
+ ClassDB::bind_method(D_METHOD("get_stage_compile_error", "stage"), &RDShaderSPIRV::get_stage_compile_error);
ADD_GROUP("Bytecode", "bytecode_");
ADD_PROPERTYI(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "bytecode_vertex"), "set_stage_bytecode", "get_stage_bytecode", RD::SHADER_STAGE_VERTEX);
@@ -288,25 +329,30 @@ protected:
class RDShaderFile : public Resource {
GDCLASS(RDShaderFile, Resource)
- Map<StringName, Ref<RDShaderBytecode>> versions;
+ Map<StringName, Ref<RDShaderSPIRV>> versions;
String base_error;
public:
- void set_bytecode(const Ref<RDShaderBytecode> &p_bytecode, const StringName &p_version = StringName()) {
+ void set_bytecode(const Ref<RDShaderSPIRV> &p_bytecode, const StringName &p_version = StringName()) {
ERR_FAIL_COND(p_bytecode.is_null());
versions[p_version] = p_bytecode;
emit_changed();
}
- Ref<RDShaderBytecode> get_bytecode(const StringName &p_version = StringName()) const {
- ERR_FAIL_COND_V(!versions.has(p_version), Ref<RDShaderBytecode>());
+ Ref<RDShaderSPIRV> get_spirv(const StringName &p_version = StringName()) const {
+ ERR_FAIL_COND_V(!versions.has(p_version), Ref<RDShaderSPIRV>());
return versions[p_version];
}
+ Vector<RD::ShaderStageSPIRVData> get_spirv_stages(const StringName &p_version = StringName()) const {
+ ERR_FAIL_COND_V(!versions.has(p_version), Vector<RD::ShaderStageSPIRVData>());
+ return versions[p_version]->get_stages();
+ }
+
Vector<StringName> get_version_list() const {
Vector<StringName> vnames;
- for (Map<StringName, Ref<RDShaderBytecode>>::Element *E = versions.front(); E; E = E->next()) {
- vnames.push_back(E->key());
+ for (const KeyValue<StringName, Ref<RDShaderSPIRV>> &E : versions) {
+ vnames.push_back(E.key);
}
vnames.sort_custom<StringName::AlphCompare>();
return vnames;
@@ -325,9 +371,9 @@ public:
if (base_error != "") {
ERR_PRINT("Error parsing shader '" + p_file + "':\n\n" + base_error);
} else {
- for (Map<StringName, Ref<RDShaderBytecode>>::Element *E = versions.front(); E; E = E->next()) {
+ for (KeyValue<StringName, Ref<RDShaderSPIRV>> &E : versions) {
for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
- String error = E->get()->get_stage_compile_error(RD::ShaderStage(i));
+ String error = E.value->get_stage_compile_error(RD::ShaderStage(i));
if (error != String()) {
static const char *stage_str[RD::SHADER_STAGE_MAX] = {
"vertex",
@@ -337,7 +383,7 @@ public:
"compute"
};
- ERR_PRINT("Error parsing shader '" + p_file + "', version '" + String(E->key()) + "', stage '" + stage_str[i] + "':\n\n" + error);
+ ERR_PRINT("Error parsing shader '" + p_file + "', version '" + String(E.key) + "', stage '" + stage_str[i] + "':\n\n" + error);
}
}
}
@@ -360,9 +406,9 @@ protected:
versions.clear();
List<Variant> keys;
p_versions.get_key_list(&keys);
- for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
- StringName name = E->get();
- Ref<RDShaderBytecode> bc = p_versions[E->get()];
+ for (const Variant &E : keys) {
+ StringName name = E;
+ Ref<RDShaderSPIRV> bc = p_versions[E];
ERR_CONTINUE(bc.is_null());
versions[name] = bc;
}
@@ -372,7 +418,7 @@ protected:
static void _bind_methods() {
ClassDB::bind_method(D_METHOD("set_bytecode", "bytecode", "version"), &RDShaderFile::set_bytecode, DEFVAL(StringName()));
- ClassDB::bind_method(D_METHOD("get_bytecode", "version"), &RDShaderFile::get_bytecode, DEFVAL(StringName()));
+ ClassDB::bind_method(D_METHOD("get_spirv", "version"), &RDShaderFile::get_spirv, DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("get_version_list"), &RDShaderFile::get_version_list);
ClassDB::bind_method(D_METHOD("set_base_error", "error"), &RDShaderFile::set_base_error);
@@ -381,13 +427,13 @@ protected:
ClassDB::bind_method(D_METHOD("_set_versions", "versions"), &RDShaderFile::_set_versions);
ClassDB::bind_method(D_METHOD("_get_versions"), &RDShaderFile::_get_versions);
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_versions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_versions", "_get_versions");
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_versions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_versions", "_get_versions");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_error"), "set_base_error", "get_base_error");
}
};
-class RDUniform : public Reference {
- GDCLASS(RDUniform, Reference)
+class RDUniform : public RefCounted {
+ GDCLASS(RDUniform, RefCounted)
friend class RenderingDevice;
RD::Uniform base;
@@ -424,8 +470,43 @@ protected:
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_ids", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_ids", "get_ids");
}
};
-class RDPipelineRasterizationState : public Reference {
- GDCLASS(RDPipelineRasterizationState, Reference)
+
+class RDPipelineSpecializationConstant : public RefCounted {
+ GDCLASS(RDPipelineSpecializationConstant, RefCounted)
+ friend class RenderingDevice;
+
+ Variant value = false;
+ uint32_t constant_id = 0;
+
+public:
+ void set_value(const Variant &p_value) {
+ ERR_FAIL_COND(p_value.get_type() != Variant::BOOL && p_value.get_type() != Variant::INT && p_value.get_type() != Variant::FLOAT);
+ value = p_value;
+ }
+ Variant get_value() const { return value; }
+
+ void set_constant_id(uint32_t p_id) {
+ constant_id = p_id;
+ }
+ uint32_t get_constant_id() const {
+ return constant_id;
+ }
+
+protected:
+ static void _bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_value", "value"), &RDPipelineSpecializationConstant::set_value);
+ ClassDB::bind_method(D_METHOD("get_value"), &RDPipelineSpecializationConstant::get_value);
+
+ ClassDB::bind_method(D_METHOD("set_constant_id", "constant_id"), &RDPipelineSpecializationConstant::set_constant_id);
+ ClassDB::bind_method(D_METHOD("get_constant_id"), &RDPipelineSpecializationConstant::get_constant_id);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_value", "get_value");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "constant_id", PROPERTY_HINT_RANGE, "0,65535,0"), "set_constant_id", "get_constant_id");
+ }
+};
+
+class RDPipelineRasterizationState : public RefCounted {
+ GDCLASS(RDPipelineRasterizationState, RefCounted)
friend class RenderingDevice;
RD::PipelineRasterizationState base;
@@ -459,8 +540,8 @@ protected:
}
};
-class RDPipelineMultisampleState : public Reference {
- GDCLASS(RDPipelineMultisampleState, Reference)
+class RDPipelineMultisampleState : public RefCounted {
+ GDCLASS(RDPipelineMultisampleState, RefCounted)
friend class RenderingDevice;
RD::PipelineMultisampleState base;
@@ -490,8 +571,8 @@ protected:
}
};
-class RDPipelineDepthStencilState : public Reference {
- GDCLASS(RDPipelineDepthStencilState, Reference)
+class RDPipelineDepthStencilState : public RefCounted {
+ GDCLASS(RDPipelineDepthStencilState, RefCounted)
friend class RenderingDevice;
RD::PipelineDepthStencilState base;
@@ -549,8 +630,8 @@ protected:
}
};
-class RDPipelineColorBlendStateAttachment : public Reference {
- GDCLASS(RDPipelineColorBlendStateAttachment, Reference)
+class RDPipelineColorBlendStateAttachment : public RefCounted {
+ GDCLASS(RDPipelineColorBlendStateAttachment, RefCounted)
friend class RenderingDevice;
RD::PipelineColorBlendState::Attachment base;
@@ -594,8 +675,8 @@ protected:
}
};
-class RDPipelineColorBlendState : public Reference {
- GDCLASS(RDPipelineColorBlendState, Reference)
+class RDPipelineColorBlendState : public RefCounted {
+ GDCLASS(RDPipelineColorBlendState, RefCounted)
friend class RenderingDevice;
RD::PipelineColorBlendState base;
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index c6fe6a07e0..2ce9a20b6b 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -38,33 +38,16 @@
#include "renderer_scene_cull.h"
#include "rendering_server_globals.h"
-// careful, these may run in different threads than the visual server
+// careful, these may run in different threads than the rendering server
int RenderingServerDefault::changes = 0;
-/* BLACK BARS */
-
-void RenderingServerDefault::black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) {
- black_margin[SIDE_LEFT] = p_left;
- black_margin[SIDE_TOP] = p_top;
- black_margin[SIDE_RIGHT] = p_right;
- black_margin[SIDE_BOTTOM] = p_bottom;
-}
-
-void RenderingServerDefault::black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) {
- black_image[SIDE_LEFT] = p_left;
- black_image[SIDE_TOP] = p_top;
- black_image[SIDE_RIGHT] = p_right;
- black_image[SIDE_BOTTOM] = p_bottom;
-}
-
-void RenderingServerDefault::_draw_margins() {
- RSG::canvas_render->draw_window_margins(black_margin, black_image);
-};
-
/* FREE */
void RenderingServerDefault::_free(RID p_rid) {
+ if (unlikely(p_rid.is_null())) {
+ return;
+ }
if (RSG::storage->free(p_rid)) {
return;
}
@@ -81,19 +64,13 @@ void RenderingServerDefault::_free(RID p_rid) {
/* EVENT QUEUING */
-void RenderingServerDefault::request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) {
- ERR_FAIL_NULL(p_where);
- FrameDrawnCallbacks fdc;
- fdc.object = p_where->get_instance_id();
- fdc.method = p_method;
- fdc.param = p_userdata;
-
- frame_drawn_callbacks.push_back(fdc);
+void RenderingServerDefault::request_frame_drawn_callback(const Callable &p_callable) {
+ frame_drawn_callbacks.push_back(p_callable);
}
void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
//needs to be done before changes is reset to 0, to not force the editor to redraw
- RS::get_singleton()->emit_signal("frame_pre_draw");
+ RS::get_singleton()->emit_signal(SNAME("frame_pre_draw"));
changes = 0;
@@ -114,24 +91,24 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
RSG::viewport->draw_viewports();
RSG::canvas_render->update();
- _draw_margins();
RSG::rasterizer->end_frame(p_swap_buffers);
+ RSG::canvas->update_visibility_notifiers();
+ RSG::scene->update_visibility_notifiers();
+
while (frame_drawn_callbacks.front()) {
- Object *obj = ObjectDB::get_instance(frame_drawn_callbacks.front()->get().object);
- if (obj) {
- Callable::CallError ce;
- const Variant *v = &frame_drawn_callbacks.front()->get().param;
- obj->call(frame_drawn_callbacks.front()->get().method, &v, 1, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- String err = Variant::get_call_error_text(obj, frame_drawn_callbacks.front()->get().method, &v, 1, ce);
- ERR_PRINT("Error calling frame drawn function: " + err);
- }
+ Callable c = frame_drawn_callbacks.front()->get();
+ Variant result;
+ Callable::CallError ce;
+ c.call(nullptr, 0, result, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ String err = Variant::get_callable_error_text(c, nullptr, 0, ce);
+ ERR_PRINT("Error calling frame drawn function: " + err);
}
frame_drawn_callbacks.pop_front();
}
- RS::get_singleton()->emit_signal("frame_post_draw");
+ RS::get_singleton()->emit_signal(SNAME("frame_post_draw"));
if (RSG::storage->get_captured_timestamps_count()) {
Vector<FrameProfileArea> new_profile;
@@ -152,8 +129,8 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
}
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].gpu_msec = double((time_gpu - base_gpu) / 1000) / 1000.0;
+ new_profile.write[i].cpu_msec = double(time_cpu - base_cpu) / 1000.0;
new_profile.write[i].name = RSG::storage->get_captured_timestamp_name(i);
}
}
@@ -167,7 +144,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
if (print_frame_profile_ticks_from == 0) {
print_frame_profile_ticks_from = OS::get_singleton()->get_ticks_usec();
}
- float total_time = 0.0;
+ double total_time = 0.0;
for (int i = 0; i < frame_profile.size() - 1; i++) {
String name = frame_profile[i].name;
@@ -175,7 +152,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
continue;
}
- float time = frame_profile[i + 1].gpu_msec - frame_profile[i].gpu_msec;
+ double time = frame_profile[i + 1].gpu_msec - frame_profile[i].gpu_msec;
if (name[0] != '<' && name[0] != '>') {
if (print_gpu_profile_task_time.has(name)) {
@@ -197,7 +174,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
float print_threshold = 0.01;
for (OrderedHashMap<String, float>::Element E = print_gpu_profile_task_time.front(); E; E = E.next()) {
- float time = E.value() / float(print_frame_profile_frame_count);
+ double time = E.value() / double(print_frame_profile_frame_count);
if (time > print_threshold) {
print_line("\t-" + E.key() + ": " + rtos(time) + "ms");
}
@@ -207,9 +184,11 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
print_frame_profile_frame_count = 0;
}
}
+
+ RSG::storage->update_memory_info();
}
-float RenderingServerDefault::get_frame_setup_time_cpu() const {
+double RenderingServerDefault::get_frame_setup_time_cpu() const {
return frame_setup_time;
}
@@ -257,8 +236,15 @@ void RenderingServerDefault::finish() {
/* STATUS INFORMATION */
-uint64_t RenderingServerDefault::get_render_info(RenderInfo p_info) {
- return RSG::storage->get_render_info(p_info);
+uint64_t RenderingServerDefault::get_rendering_info(RenderingInfo p_info) {
+ if (p_info == RENDERING_INFO_TOTAL_OBJECTS_IN_FRAME) {
+ return RSG::viewport->get_total_objects_drawn();
+ } else if (p_info == RENDERING_INFO_TOTAL_PRIMITIVES_IN_FRAME) {
+ return RSG::viewport->get_total_vertices_drawn();
+ } else if (p_info == RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME) {
+ return RSG::viewport->get_total_draw_calls_used();
+ }
+ return RSG::storage->get_rendering_info(p_info);
}
String RenderingServerDefault::get_video_adapter_name() const {
@@ -358,7 +344,7 @@ void RenderingServerDefault::_thread_loop() {
draw_thread_up.set();
while (!exit.is_set()) {
// flush commands one by one, until exit is requested
- command_queue.wait_and_flush_one();
+ command_queue.wait_and_flush();
}
command_queue.flush_all(); // flush all
@@ -396,6 +382,7 @@ RenderingServerDefault::RenderingServerDefault(bool p_create_thread) :
server_thread = 0;
}
+ RSG::threaded = p_create_thread;
RSG::canvas = memnew(RendererCanvasCull);
RSG::viewport = memnew(RendererViewport);
RendererSceneCull *sr = memnew(RendererSceneCull);
@@ -406,11 +393,6 @@ RenderingServerDefault::RenderingServerDefault(bool p_create_thread) :
sr->set_scene_render(RSG::rasterizer->get_scene());
frame_profile_frame = 0;
-
- for (int i = 0; i < 4; i++) {
- black_margin[i] = 0;
- black_image[i] = RID();
- }
}
RenderingServerDefault::~RenderingServerDefault() {
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index bf47d497b6..b50631bb21 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -58,24 +58,14 @@ class RenderingServerDefault : public RenderingServer {
static int changes;
RID test_cube;
- int black_margin[4];
- RID black_image[4];
+ List<Callable> frame_drawn_callbacks;
- struct FrameDrawnCallbacks {
- ObjectID object;
- StringName method;
- Variant param;
- };
-
- List<FrameDrawnCallbacks> frame_drawn_callbacks;
-
- void _draw_margins();
static void _changes_changed() {}
uint64_t frame_profile_frame;
Vector<FrameProfileArea> frame_profile;
- float frame_setup_time = 0;
+ double frame_setup_time = 0;
//for printing
bool print_gpu_profile = false;
@@ -192,8 +182,6 @@ public:
FUNCRIDTEX6(texture_3d, Image::Format, int, int, int, bool, const Vector<Ref<Image>> &)
FUNCRIDTEX1(texture_proxy, RID)
- //goes pass-through
- FUNC3(texture_2d_update_immediate, RID, const Ref<Image> &, int)
//these go through command queue if they are in another thread
FUNC3(texture_2d_update, RID, const Ref<Image> &, int)
FUNC2(texture_3d_update, RID, const Vector<Ref<Image>> &)
@@ -235,8 +223,8 @@ public:
FUNC2SC(shader_get_param_list, RID, List<PropertyInfo> *)
- FUNC3(shader_set_default_texture_param, RID, const StringName &, RID)
- FUNC2RC(RID, shader_get_default_texture_param, RID, const StringName &)
+ FUNC4(shader_set_default_texture_param, RID, const StringName &, RID, int)
+ FUNC3RC(RID, shader_get_default_texture_param, RID, const StringName &, int)
FUNC2RC(Variant, shader_get_param_default, RID, const StringName &)
FUNC1RC(ShaderNativeSourceCode, shader_get_native_source_code, RID)
@@ -290,7 +278,9 @@ public:
FUNC2(mesh_set_blend_shape_mode, RID, BlendShapeMode)
FUNC1RC(BlendShapeMode, mesh_get_blend_shape_mode, RID)
- FUNC4(mesh_surface_update_region, RID, int, int, const Vector<uint8_t> &)
+ FUNC4(mesh_surface_update_vertex_region, RID, int, int, const Vector<uint8_t> &)
+ FUNC4(mesh_surface_update_attribute_region, RID, int, int, const Vector<uint8_t> &)
+ FUNC4(mesh_surface_update_skin_region, RID, int, int, const Vector<uint8_t> &)
FUNC3(mesh_surface_set_material, RID, int, RID)
FUNC2RC(RID, mesh_surface_get_material, RID, int)
@@ -314,7 +304,7 @@ public:
FUNC1RC(int, multimesh_get_instance_count, RID)
FUNC2(multimesh_set_mesh, RID, RID)
- FUNC3(multimesh_instance_set_transform, RID, int, const Transform &)
+ FUNC3(multimesh_instance_set_transform, RID, int, const Transform3D &)
FUNC3(multimesh_instance_set_transform_2d, RID, int, const Transform2D &)
FUNC3(multimesh_instance_set_color, RID, int, const Color &)
FUNC3(multimesh_instance_set_custom_data, RID, int, const Color &)
@@ -322,7 +312,7 @@ public:
FUNC1RC(RID, multimesh_get_mesh, RID)
FUNC1RC(AABB, multimesh_get_aabb, RID)
- FUNC2RC(Transform, multimesh_instance_get_transform, RID, int)
+ FUNC2RC(Transform3D, multimesh_instance_get_transform, RID, int)
FUNC2RC(Transform2D, multimesh_instance_get_transform_2d, RID, int)
FUNC2RC(Color, multimesh_instance_get_color, RID, int)
FUNC2RC(Color, multimesh_instance_get_custom_data, RID, int)
@@ -333,28 +323,13 @@ public:
FUNC2(multimesh_set_visible_instances, RID, int)
FUNC1RC(int, multimesh_get_visible_instances, RID)
- /* IMMEDIATE API */
-
- FUNCRIDSPLIT(immediate)
- FUNC3(immediate_begin, RID, PrimitiveType, RID)
- FUNC2(immediate_vertex, RID, const Vector3 &)
- FUNC2(immediate_normal, RID, const Vector3 &)
- FUNC2(immediate_tangent, RID, const Plane &)
- FUNC2(immediate_color, RID, const Color &)
- FUNC2(immediate_uv, RID, const Vector2 &)
- FUNC2(immediate_uv2, RID, const Vector2 &)
- FUNC1(immediate_end, RID)
- FUNC1(immediate_clear, RID)
- FUNC2(immediate_set_material, RID, RID)
- FUNC1RC(RID, immediate_get_material, RID)
-
/* SKELETON API */
FUNCRIDSPLIT(skeleton)
FUNC3(skeleton_allocate_data, RID, int, bool)
FUNC1RC(int, skeleton_get_bone_count, RID)
- FUNC3(skeleton_bone_set_transform, RID, int, const Transform &)
- FUNC2RC(Transform, skeleton_bone_get_transform, RID, int)
+ FUNC3(skeleton_bone_set_transform, RID, int, const Transform3D &)
+ FUNC2RC(Transform3D, skeleton_bone_get_transform, RID, int)
FUNC3(skeleton_bone_set_transform_2d, RID, int, const Transform2D &)
FUNC2RC(Transform2D, skeleton_bone_get_transform_2d, RID, int)
FUNC2(skeleton_set_base_transform_2d, RID, const Transform2D &)
@@ -381,7 +356,6 @@ public:
FUNC2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode)
FUNC2(light_directional_set_blend_splits, RID, bool)
FUNC2(light_directional_set_sky_only, RID, bool)
- FUNC2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode)
/* PROBE API */
@@ -418,47 +392,25 @@ public:
/* BAKED LIGHT API */
- FUNCRIDSPLIT(gi_probe)
-
- FUNC8(gi_probe_allocate_data, RID, const Transform &, const AABB &, const Vector3i &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<int> &)
-
- FUNC1RC(AABB, gi_probe_get_bounds, RID)
- FUNC1RC(Vector3i, gi_probe_get_octree_size, RID)
- FUNC1RC(Vector<uint8_t>, gi_probe_get_octree_cells, RID)
- FUNC1RC(Vector<uint8_t>, gi_probe_get_data_cells, RID)
- FUNC1RC(Vector<uint8_t>, gi_probe_get_distance_field, RID)
- FUNC1RC(Vector<int>, gi_probe_get_level_counts, RID)
- FUNC1RC(Transform, gi_probe_get_to_cell_xform, RID)
-
- FUNC2(gi_probe_set_dynamic_range, RID, float)
- FUNC1RC(float, gi_probe_get_dynamic_range, RID)
-
- FUNC2(gi_probe_set_propagation, RID, float)
- FUNC1RC(float, gi_probe_get_propagation, RID)
-
- FUNC2(gi_probe_set_energy, RID, float)
- FUNC1RC(float, gi_probe_get_energy, RID)
-
- FUNC2(gi_probe_set_ao, RID, float)
- FUNC1RC(float, gi_probe_get_ao, RID)
-
- FUNC2(gi_probe_set_ao_size, RID, float)
- FUNC1RC(float, gi_probe_get_ao_size, RID)
-
- FUNC2(gi_probe_set_bias, RID, float)
- FUNC1RC(float, gi_probe_get_bias, RID)
-
- FUNC2(gi_probe_set_normal_bias, RID, float)
- FUNC1RC(float, gi_probe_get_normal_bias, RID)
+ FUNCRIDSPLIT(voxel_gi)
- FUNC2(gi_probe_set_interior, RID, bool)
- FUNC1RC(bool, gi_probe_is_interior, RID)
+ FUNC8(voxel_gi_allocate_data, RID, const Transform3D &, const AABB &, const Vector3i &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<int> &)
- FUNC2(gi_probe_set_use_two_bounces, RID, bool)
- FUNC1RC(bool, gi_probe_is_using_two_bounces, RID)
+ FUNC1RC(AABB, voxel_gi_get_bounds, RID)
+ FUNC1RC(Vector3i, voxel_gi_get_octree_size, RID)
+ FUNC1RC(Vector<uint8_t>, voxel_gi_get_octree_cells, RID)
+ FUNC1RC(Vector<uint8_t>, voxel_gi_get_data_cells, RID)
+ FUNC1RC(Vector<uint8_t>, voxel_gi_get_distance_field, RID)
+ FUNC1RC(Vector<int>, voxel_gi_get_level_counts, RID)
+ FUNC1RC(Transform3D, voxel_gi_get_to_cell_xform, RID)
- FUNC2(gi_probe_set_anisotropy_strength, RID, float)
- FUNC1RC(float, gi_probe_get_anisotropy_strength, RID)
+ FUNC2(voxel_gi_set_dynamic_range, RID, float)
+ FUNC2(voxel_gi_set_propagation, RID, float)
+ FUNC2(voxel_gi_set_energy, RID, float)
+ FUNC2(voxel_gi_set_bias, RID, float)
+ FUNC2(voxel_gi_set_normal_bias, RID, float)
+ FUNC2(voxel_gi_set_interior, RID, bool)
+ FUNC2(voxel_gi_set_use_two_bounces, RID, bool)
/* LIGHTMAP */
@@ -482,13 +434,13 @@ public:
FUNC2(particles_set_emitting, RID, bool)
FUNC1R(bool, particles_get_emitting, RID)
FUNC2(particles_set_amount, RID, int)
- FUNC2(particles_set_lifetime, RID, float)
+ FUNC2(particles_set_lifetime, RID, double)
FUNC2(particles_set_one_shot, RID, bool)
- FUNC2(particles_set_pre_process_time, RID, float)
+ FUNC2(particles_set_pre_process_time, RID, double)
FUNC2(particles_set_explosiveness_ratio, RID, float)
FUNC2(particles_set_randomness_ratio, RID, float)
FUNC2(particles_set_custom_aabb, RID, const AABB &)
- FUNC2(particles_set_speed_scale, RID, float)
+ FUNC2(particles_set_speed_scale, RID, double)
FUNC2(particles_set_use_local_coordinates, RID, bool)
FUNC2(particles_set_process_material, RID, RID)
FUNC2(particles_set_fixed_fps, RID, int)
@@ -496,11 +448,11 @@ public:
FUNC2(particles_set_fractional_delta, RID, bool)
FUNC1R(bool, particles_is_inactive, RID)
FUNC3(particles_set_trails, RID, bool, float)
- FUNC2(particles_set_trail_bind_poses, RID, const Vector<Transform> &)
+ FUNC2(particles_set_trail_bind_poses, RID, const Vector<Transform3D> &)
FUNC1(particles_request_process, RID)
FUNC1(particles_restart, RID)
- FUNC6(particles_emit, RID, const Transform &, const Vector3 &, const Color &, const Color &, uint32_t)
+ FUNC6(particles_emit, RID, const Transform3D &, const Vector3 &, const Color &, const Color &, uint32_t)
FUNC2(particles_set_subemitter, RID, RID)
FUNC2(particles_set_collision_base_size, RID, float)
@@ -512,7 +464,7 @@ public:
FUNC3(particles_set_draw_pass_mesh, RID, int, RID)
FUNC1R(AABB, particles_get_current_aabb, RID)
- FUNC2(particles_set_emission_transform, RID, const Transform &)
+ FUNC2(particles_set_emission_transform, RID, const Transform3D &)
/* PARTICLES COLLISION */
@@ -520,15 +472,29 @@ public:
FUNC2(particles_collision_set_collision_type, RID, ParticlesCollisionType)
FUNC2(particles_collision_set_cull_mask, RID, uint32_t)
- FUNC2(particles_collision_set_sphere_radius, RID, float)
+ FUNC2(particles_collision_set_sphere_radius, RID, real_t)
FUNC2(particles_collision_set_box_extents, RID, const Vector3 &)
- FUNC2(particles_collision_set_attractor_strength, RID, float)
- FUNC2(particles_collision_set_attractor_directionality, RID, float)
- FUNC2(particles_collision_set_attractor_attenuation, RID, float)
+ FUNC2(particles_collision_set_attractor_strength, RID, real_t)
+ FUNC2(particles_collision_set_attractor_directionality, RID, real_t)
+ FUNC2(particles_collision_set_attractor_attenuation, RID, real_t)
FUNC2(particles_collision_set_field_texture, RID, RID)
FUNC1(particles_collision_height_field_update, RID)
FUNC2(particles_collision_set_height_field_resolution, RID, ParticlesCollisionHeightfieldResolution)
+ /* FOG VOLUME */
+
+ FUNCRIDSPLIT(fog_volume)
+
+ FUNC2(fog_volume_set_shape, RID, FogVolumeShape)
+ FUNC2(fog_volume_set_extents, RID, const Vector3 &)
+ FUNC2(fog_volume_set_material, RID, RID)
+
+ /* VISIBILITY_NOTIFIER */
+
+ FUNCRIDSPLIT(visibility_notifier)
+ FUNC2(visibility_notifier_set_aabb, RID, const AABB &)
+ FUNC3(visibility_notifier_set_callbacks, RID, const Callable &, const Callable &)
+
#undef server_name
#undef ServerName
//from now on, calls forwarded to this singleton
@@ -541,7 +507,7 @@ public:
FUNC4(camera_set_perspective, RID, float, float, float)
FUNC4(camera_set_orthogonal, RID, float, float, float)
FUNC5(camera_set_frustum, RID, float, Vector2, float, float)
- FUNC2(camera_set_transform, RID, const Transform &)
+ FUNC2(camera_set_transform, RID, const Transform3D &)
FUNC2(camera_set_cull_mask, RID, uint32_t)
FUNC2(camera_set_environment, RID, RID)
FUNC2(camera_set_camera_effects, RID, RID)
@@ -549,7 +515,7 @@ public:
/* OCCLUDER */
FUNCRIDSPLIT(occluder)
- FUNC3(occluder_set_mesh, RID, const PackedVector3Array &, const PackedInt32Array &);
+ FUNC3(occluder_set_mesh, RID, const PackedVector3Array &, const PackedInt32Array &)
#undef server_name
#undef ServerName
@@ -572,13 +538,18 @@ public:
FUNC3(viewport_attach_to_screen, RID, const Rect2 &, int)
FUNC2(viewport_set_render_direct_to_screen, RID, bool)
+ FUNC2(viewport_set_scaling_3d_mode, RID, ViewportScaling3DMode)
+ FUNC2(viewport_set_scaling_3d_scale, RID, float)
+ FUNC2(viewport_set_fsr_sharpness, RID, float)
+ FUNC2(viewport_set_fsr_mipmap_bias, RID, float)
+
FUNC2(viewport_set_update_mode, RID, ViewportUpdateMode)
FUNC1RC(RID, viewport_get_texture, RID)
- FUNC2(viewport_set_hide_scenario, RID, bool)
- FUNC2(viewport_set_hide_canvas, RID, bool)
+ FUNC2(viewport_set_disable_2d, RID, bool)
FUNC2(viewport_set_disable_environment, RID, bool)
+ FUNC2(viewport_set_disable_3d, RID, bool)
FUNC2(viewport_attach_camera, RID, RID)
FUNC2(viewport_set_scenario, RID, RID)
@@ -606,14 +577,14 @@ public:
FUNC1(viewport_set_occlusion_culling_build_quality, ViewportOcclusionCullingBuildQuality)
FUNC2(viewport_set_lod_threshold, RID, float)
- FUNC2R(int, viewport_get_render_info, RID, ViewportRenderInfo)
+ FUNC3R(int, viewport_get_render_info, RID, ViewportRenderInfoType, ViewportRenderInfo)
FUNC2(viewport_set_debug_draw, RID, ViewportDebugDraw)
FUNC2(viewport_set_measure_render_time, RID, bool)
- FUNC1RC(float, viewport_get_measured_render_time_cpu, RID)
- FUNC1RC(float, viewport_get_measured_render_time_gpu, RID)
+ FUNC1RC(double, viewport_get_measured_render_time_cpu, RID)
+ FUNC1RC(double, viewport_get_measured_render_time_gpu, RID)
- FUNC1(call_set_use_vsync, bool)
+ FUNC2(call_set_vsync_mode, DisplayServer::VSyncMode, DisplayServer::WindowID)
/* ENVIRONMENT API */
@@ -624,7 +595,7 @@ public:
#define server_name RSG::scene
FUNC2(directional_shadow_atlas_set_size, int, bool)
- FUNC1(gi_probe_set_quality, GIProbeQuality)
+ FUNC1(voxel_gi_set_quality, VoxelGIQuality)
/* SKY API */
@@ -643,7 +614,7 @@ public:
FUNC2(environment_set_bg_color, RID, const Color &)
FUNC2(environment_set_bg_energy, RID, float)
FUNC2(environment_set_canvas_max_layer, RID, int)
- FUNC7(environment_set_ambient_light, RID, const Color &, EnvironmentAmbientSource, float, float, EnvironmentReflectionSource, const Color &)
+ FUNC6(environment_set_ambient_light, RID, const Color &, EnvironmentAmbientSource, float, float, EnvironmentReflectionSource)
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
@@ -664,7 +635,7 @@ public:
FUNC7(environment_set_adjustment, RID, bool, float, float, float, bool, RID)
FUNC9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float)
- FUNC10(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, bool, float)
+ FUNC13(environment_set_volumetric_fog, RID, bool, float, const Color &, const Color &, float, float, float, float, float, bool, float, float)
FUNC2(environment_set_volumetric_fog_volume_size, int, int)
FUNC1(environment_set_volumetric_fog_filter_active, bool)
@@ -692,6 +663,8 @@ public:
FUNC1(shadows_quality_set, ShadowQuality);
FUNC1(directional_shadow_quality_set, ShadowQuality);
+ FUNC1(decals_set_filter, RS::DecalFilter);
+ FUNC1(light_projectors_set_filter, RS::LightProjectorFilter);
/* SCENARIO API */
@@ -703,7 +676,6 @@ public:
FUNCRIDSPLIT(scenario)
- FUNC2(scenario_set_debug, RID, ScenarioDebugMode)
FUNC2(scenario_set_environment, RID, RID)
FUNC2(scenario_set_camera_effects, RID, RID)
FUNC2(scenario_set_fallback_environment, RID, RID)
@@ -714,7 +686,7 @@ public:
FUNC2(instance_set_base, RID, RID)
FUNC2(instance_set_scenario, RID, RID)
FUNC2(instance_set_layer_mask, RID, uint32_t)
- FUNC2(instance_set_transform, RID, const Transform &)
+ FUNC2(instance_set_transform, RID, const Transform3D &)
FUNC2(instance_attach_object_instance_id, RID, ObjectID)
FUNC3(instance_set_blend_shape_weight, RID, int, float)
FUNC3(instance_set_surface_override_material, RID, int, RID)
@@ -723,9 +695,11 @@ public:
FUNC2(instance_set_custom_aabb, RID, AABB)
FUNC2(instance_attach_skeleton, RID, RID)
- FUNC2(instance_set_exterior, RID, bool)
FUNC2(instance_set_extra_visibility_margin, RID, real_t)
+ FUNC2(instance_set_visibility_parent, RID, RID)
+
+ FUNC2(instance_set_ignore_culling, RID, bool)
// don't use these in a game!
FUNC2RC(Vector<ObjectID>, instances_cull_aabb, const AABB &, RID)
@@ -736,11 +710,10 @@ public:
FUNC2(instance_geometry_set_cast_shadows_setting, RID, ShadowCastingSetting)
FUNC2(instance_geometry_set_material_override, RID, RID)
- FUNC5(instance_geometry_set_draw_range, RID, float, float, float, float)
- FUNC2(instance_geometry_set_as_instance_lod, RID, RID)
+ FUNC6(instance_geometry_set_visibility_range, RID, float, float, float, float, VisibilityRangeFadeMode)
FUNC4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int)
FUNC2(instance_geometry_set_lod_bias, RID, float)
-
+ FUNC2(instance_geometry_set_transparency, RID, float)
FUNC3(instance_geometry_set_shader_parameter, RID, const StringName &, const Variant &)
FUNC2RC(Variant, instance_geometry_get_shader_parameter, RID, const StringName &)
FUNC2RC(Variant, instance_geometry_get_shader_parameter_default_value, RID, const StringName &)
@@ -798,6 +771,7 @@ public:
FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &)
FUNC6(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool)
FUNC7(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, bool)
+ FUNC7(canvas_item_add_msdf_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, int, float)
FUNC10(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &)
FUNC6(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float)
FUNC5(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID)
@@ -807,6 +781,8 @@ public:
FUNC3(canvas_item_add_particles, RID, RID, RID)
FUNC2(canvas_item_add_set_transform, RID, const Transform2D &)
FUNC2(canvas_item_add_clip_ignore, RID, bool)
+ FUNC5(canvas_item_add_animation_slice, RID, double, double, double, double)
+
FUNC2(canvas_item_set_sort_children_by_y, RID, bool)
FUNC2(canvas_item_set_z_index, RID, int)
FUNC2(canvas_item_set_z_as_relative_to_parent, RID, bool)
@@ -820,6 +796,8 @@ public:
FUNC2(canvas_item_set_use_parent_material, RID, bool)
+ FUNC5(canvas_item_set_visibility_notifier, RID, bool, const Rect2 &, const Callable &, const Callable &)
+
FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool)
FUNCRIDSPLIT(canvas_light)
@@ -887,11 +865,6 @@ public:
#undef WRITE_ACTION
#undef SYNC_DEBUG
- /* BLACK BARS */
-
- virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) override;
- virtual void black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) override;
-
/* FREE */
virtual void free(RID p_rid) override {
@@ -905,7 +878,7 @@ public:
/* EVENT QUEUING */
- virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) override;
+ virtual void request_frame_drawn_callback(const Callable &p_callable) override;
virtual void draw(bool p_swap_buffers, double frame_step) override;
virtual void sync() override;
@@ -915,7 +888,7 @@ public:
/* STATUS INFORMATION */
- virtual uint64_t get_render_info(RenderInfo p_info) override;
+ virtual uint64_t get_rendering_info(RenderingInfo p_info) override;
virtual String get_video_adapter_name() const override;
virtual String get_video_adapter_vendor() const override;
@@ -927,7 +900,7 @@ public:
/* TESTING */
- virtual float get_frame_setup_time_cpu() const override;
+ virtual double get_frame_setup_time_cpu() const override;
virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) override;
virtual void set_default_clear_color(const Color &p_color) override;
diff --git a/servers/rendering/rendering_server_globals.cpp b/servers/rendering/rendering_server_globals.cpp
index c0d9988e85..2dda506bac 100644
--- a/servers/rendering/rendering_server_globals.cpp
+++ b/servers/rendering/rendering_server_globals.cpp
@@ -30,6 +30,8 @@
#include "rendering_server_globals.h"
+bool RenderingServerGlobals::threaded = false;
+
RendererStorage *RenderingServerGlobals::storage = nullptr;
RendererCanvasRender *RenderingServerGlobals::canvas_render = nullptr;
RendererCompositor *RenderingServerGlobals::rasterizer = nullptr;
diff --git a/servers/rendering/rendering_server_globals.h b/servers/rendering/rendering_server_globals.h
index a28a0f5180..63755e6125 100644
--- a/servers/rendering/rendering_server_globals.h
+++ b/servers/rendering/rendering_server_globals.h
@@ -41,6 +41,8 @@ class RendererScene;
class RenderingServerGlobals {
public:
+ static bool threaded;
+
static RendererStorage *storage;
static RendererCanvasRender *canvas_render;
static RendererCompositor *rasterizer;
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index a81306b97d..50719ecfc3 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -33,6 +33,8 @@
#include "core/string/print_string.h"
#include "servers/rendering_server.h"
+#define HAS_WARNING(flag) (warning_flags & flag)
+
static bool _is_text_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
@@ -629,7 +631,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
if (!_is_number(last_char)) {
return _make_token(TK_ERROR, "Invalid (integer) numeric constant");
}
- if (!str.is_valid_integer()) {
+ if (!str.is_valid_int()) {
return _make_token(TK_ERROR, "Invalid numeric constant");
}
}
@@ -901,6 +903,8 @@ bool ShaderLanguage::is_token_nonvoid_datatype(TokenType p_type) {
void ShaderLanguage::clear() {
current_function = StringName();
+ last_name = StringName();
+ last_type = IDENTIFIER_MAX;
completion_type = COMPLETION_NONE;
completion_block = nullptr;
@@ -908,6 +912,18 @@ void ShaderLanguage::clear() {
completion_class = SubClassTag::TAG_GLOBAL;
completion_struct = StringName();
+ unknown_varying_usages.clear();
+
+#ifdef DEBUG_ENABLED
+ used_constants.clear();
+ used_varyings.clear();
+ used_uniforms.clear();
+ used_functions.clear();
+ used_structs.clear();
+ used_local_vars.clear();
+ warnings.clear();
+#endif // DEBUG_ENABLED
+
error_line = 0;
tk_line = 1;
char_idx = 0;
@@ -921,6 +937,42 @@ void ShaderLanguage::clear() {
}
}
+#ifdef DEBUG_ENABLED
+void ShaderLanguage::_parse_used_identifier(const StringName &p_identifier, IdentifierType p_type, const StringName &p_function) {
+ switch (p_type) {
+ case IdentifierType::IDENTIFIER_CONSTANT:
+ if (HAS_WARNING(ShaderWarning::UNUSED_CONSTANT_FLAG) && used_constants.has(p_identifier)) {
+ used_constants[p_identifier].used = true;
+ }
+ break;
+ case IdentifierType::IDENTIFIER_VARYING:
+ if (HAS_WARNING(ShaderWarning::UNUSED_VARYING_FLAG) && used_varyings.has(p_identifier)) {
+ if (shader->varyings[p_identifier].stage != ShaderNode::Varying::STAGE_VERTEX && shader->varyings[p_identifier].stage != ShaderNode::Varying::STAGE_FRAGMENT) {
+ used_varyings[p_identifier].used = true;
+ }
+ }
+ break;
+ case IdentifierType::IDENTIFIER_UNIFORM:
+ if (HAS_WARNING(ShaderWarning::UNUSED_UNIFORM_FLAG) && used_uniforms.has(p_identifier)) {
+ used_uniforms[p_identifier].used = true;
+ }
+ break;
+ case IdentifierType::IDENTIFIER_FUNCTION:
+ if (HAS_WARNING(ShaderWarning::UNUSED_FUNCTION_FLAG) && used_functions.has(p_identifier)) {
+ used_functions[p_identifier].used = true;
+ }
+ break;
+ case IdentifierType::IDENTIFIER_LOCAL_VAR:
+ if (HAS_WARNING(ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG) && used_local_vars.has(p_function) && used_local_vars[p_function].has(p_identifier)) {
+ used_local_vars[p_function][p_identifier].used = true;
+ }
+ break;
+ default:
+ break;
+ }
+}
+#endif // DEBUG_ENABLED
+
bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name, ConstantNode::Value *r_constant_value) {
if (p_function_info.built_ins.has(p_identifier)) {
if (r_data_type) {
@@ -932,7 +984,6 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_type) {
*r_type = IDENTIFIER_BUILTIN_VAR;
}
-
return true;
}
@@ -946,7 +997,6 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_type) {
*r_type = IDENTIFIER_FUNCTION;
}
-
return true;
}
@@ -963,16 +1013,15 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_array_size) {
*r_array_size = p_block->variables[p_identifier].array_size;
}
- if (r_type) {
- *r_type = IDENTIFIER_LOCAL_VAR;
- }
if (r_struct_name) {
*r_struct_name = p_block->variables[p_identifier].struct_name;
}
if (r_constant_value) {
*r_constant_value = p_block->variables[p_identifier].value;
}
-
+ if (r_type) {
+ *r_type = IDENTIFIER_LOCAL_VAR;
+ }
return true;
}
@@ -994,15 +1043,18 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_data_type) {
*r_data_type = function->arguments[i].type;
}
- if (r_type) {
- *r_type = IDENTIFIER_FUNCTION_ARGUMENT;
- }
if (r_struct_name) {
*r_struct_name = function->arguments[i].type_str;
}
+ if (r_array_size) {
+ *r_array_size = function->arguments[i].array_size;
+ }
if (r_is_const) {
*r_is_const = function->arguments[i].is_const;
}
+ if (r_type) {
+ *r_type = IDENTIFIER_FUNCTION_ARGUMENT;
+ }
return true;
}
}
@@ -1025,6 +1077,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_data_type) {
*r_data_type = shader->uniforms[p_identifier].type;
}
+ if (r_array_size) {
+ *r_array_size = shader->uniforms[p_identifier].array_size;
+ }
if (r_type) {
*r_type = IDENTIFIER_UNIFORM;
}
@@ -1041,9 +1096,6 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_array_size) {
*r_array_size = shader->constants[p_identifier].array_size;
}
- if (r_type) {
- *r_type = IDENTIFIER_CONSTANT;
- }
if (r_struct_name) {
*r_struct_name = shader->constants[p_identifier].type_str;
}
@@ -1052,6 +1104,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
*r_constant_value = shader->constants[p_identifier].initializer->values[0];
}
}
+ if (r_type) {
+ *r_type = IDENTIFIER_CONSTANT;
+ }
return true;
}
@@ -1064,6 +1119,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_data_type) {
*r_data_type = shader->functions[i].function->return_type;
}
+ if (r_array_size) {
+ *r_array_size = shader->functions[i].function->return_array_size;
+ }
if (r_type) {
*r_type = IDENTIFIER_FUNCTION;
}
@@ -1074,13 +1132,18 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
return false;
}
-bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type) {
+bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type, int *r_ret_size) {
bool valid = false;
DataType ret_type = TYPE_VOID;
+ int ret_size = 0;
switch (p_op->op) {
case OP_EQUAL:
case OP_NOT_EQUAL: {
+ if ((!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) || (!p_op->arguments[1]->is_indexed() && p_op->arguments[1]->get_array_size() > 0)) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
valid = na == nb;
@@ -1090,6 +1153,10 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
case OP_LESS_EQUAL:
case OP_GREATER:
case OP_GREATER_EQUAL: {
+ if ((!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) || (!p_op->arguments[1]->is_indexed() && p_op->arguments[1]->get_array_size() > 0)) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
@@ -1099,6 +1166,10 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
} break;
case OP_AND:
case OP_OR: {
+ if ((!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) || (!p_op->arguments[1]->is_indexed() && p_op->arguments[1]->get_array_size() > 0)) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
@@ -1107,6 +1178,10 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
} break;
case OP_NOT: {
+ if (!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
valid = na == TYPE_BOOL;
ret_type = TYPE_BOOL;
@@ -1117,6 +1192,10 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
case OP_POST_INCREMENT:
case OP_POST_DECREMENT:
case OP_NEGATE: {
+ if (!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
valid = na > TYPE_BOOL && na < TYPE_MAT2;
ret_type = na;
@@ -1125,6 +1204,10 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
case OP_SUB:
case OP_MUL:
case OP_DIV: {
+ if ((!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) || (!p_op->arguments[1]->is_indexed() && p_op->arguments[1]->get_array_size() > 0)) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
@@ -1193,6 +1276,10 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
* component-wise.
*/
+ if ((!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) || (!p_op->arguments[1]->is_indexed() && p_op->arguments[1]->get_array_size() > 0)) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
@@ -1245,6 +1332,10 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
case OP_ASSIGN_SHIFT_RIGHT:
case OP_SHIFT_LEFT:
case OP_SHIFT_RIGHT: {
+ if ((!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) || (!p_op->arguments[1]->is_indexed() && p_op->arguments[1]->get_array_size() > 0)) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
@@ -1293,6 +1384,18 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
}
} break;
case OP_ASSIGN: {
+ int sa = 0;
+ int sb = 0;
+ if (!p_op->arguments[0]->is_indexed()) {
+ sa = p_op->arguments[0]->get_array_size();
+ }
+ if (!p_op->arguments[1]->is_indexed()) {
+ sb = p_op->arguments[1]->get_array_size();
+ }
+ if (sa != sb) {
+ break; // don't accept arrays if their sizes are not equal
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
if (na == TYPE_STRUCT || nb == TYPE_STRUCT) {
@@ -1301,16 +1404,29 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
valid = na == nb;
}
ret_type = na;
+ ret_size = sa;
} break;
case OP_ASSIGN_ADD:
case OP_ASSIGN_SUB:
case OP_ASSIGN_MUL:
case OP_ASSIGN_DIV: {
+ int sa = 0;
+ int sb = 0;
+ if (!p_op->arguments[0]->is_indexed()) {
+ sa = p_op->arguments[0]->get_array_size();
+ }
+ if (!p_op->arguments[1]->is_indexed()) {
+ sb = p_op->arguments[1]->get_array_size();
+ }
+ if (sa > 0 || sb > 0) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
if (na == nb) {
- valid = (na > TYPE_BOOL && na < TYPE_MAT2) || (p_op->op == OP_ASSIGN_MUL && na >= TYPE_MAT2 && na <= TYPE_MAT4);
+ valid = (na > TYPE_BOOL && na <= TYPE_MAT4);
ret_type = na;
} else if (na == TYPE_IVEC2 && nb == TYPE_INT) {
valid = true;
@@ -1373,6 +1489,18 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
* must match.
*/
+ int sa = 0;
+ int sb = 0;
+ if (!p_op->arguments[0]->is_indexed()) {
+ sa = p_op->arguments[0]->get_array_size();
+ }
+ if (!p_op->arguments[1]->is_indexed()) {
+ sb = p_op->arguments[1]->get_array_size();
+ }
+ if (sa > 0 || sb > 0) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
@@ -1427,17 +1555,34 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
}
} break;
case OP_BIT_INVERT: { //unaries
+ if (!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
valid = na >= TYPE_INT && na < TYPE_FLOAT;
ret_type = na;
} break;
case OP_SELECT_IF: {
+ int sa = 0;
+ int sb = 0;
+ if (!p_op->arguments[1]->is_indexed()) {
+ sa = p_op->arguments[1]->get_array_size();
+ }
+ if (!p_op->arguments[2]->is_indexed()) {
+ sb = p_op->arguments[2]->get_array_size();
+ }
+ if (sa != sb) {
+ break; // don't accept arrays if their sizes are not equal
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
DataType nc = p_op->arguments[2]->get_datatype();
valid = na == TYPE_BOOL && (nb == nc);
ret_type = nb;
+ ret_size = sa;
} break;
default: {
ERR_FAIL_V(false);
@@ -1447,734 +1592,1066 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
if (r_ret_type) {
*r_ret_type = ret_type;
}
+ if (r_ret_size) {
+ *r_ret_size = ret_size;
+ }
return valid;
}
const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
- //constructors
- { "bool", TYPE_BOOL, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec2", TYPE_BVEC2, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec2", TYPE_BVEC2, { TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec3", TYPE_BVEC3, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec3", TYPE_BVEC3, { TYPE_BOOL, TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec3", TYPE_BVEC3, { TYPE_BVEC2, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec3", TYPE_BVEC3, { TYPE_BOOL, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BOOL, TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BVEC2, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BVEC2, TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BOOL, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BVEC3, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BVEC2, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "float", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec2", TYPE_VEC2, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec2", TYPE_VEC2, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec3", TYPE_VEC3, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec3", TYPE_VEC3, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec3", TYPE_VEC3, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec3", TYPE_VEC3, { TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_VEC2, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "int", TYPE_INT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec2", TYPE_IVEC2, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec2", TYPE_IVEC2, { TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec3", TYPE_IVEC3, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec3", TYPE_IVEC3, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec3", TYPE_IVEC3, { TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec3", TYPE_IVEC3, { TYPE_INT, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_IVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_INT, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "uint", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec2", TYPE_UVEC2, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec2", TYPE_UVEC2, { TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec3", TYPE_UVEC3, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec3", TYPE_UVEC3, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec3", TYPE_UVEC3, { TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec3", TYPE_UVEC3, { TYPE_UINT, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UVEC2, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UINT, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UVEC3, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "mat2", TYPE_MAT2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat3", TYPE_MAT3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat4", TYPE_MAT4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "mat2", TYPE_MAT2, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat3", TYPE_MAT3, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat4", TYPE_MAT4, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- //conversion scalars
-
- { "int", TYPE_INT, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "int", TYPE_INT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "int", TYPE_INT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "int", TYPE_INT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "float", TYPE_FLOAT, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "float", TYPE_FLOAT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "float", TYPE_FLOAT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "float", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "uint", TYPE_UINT, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, true },
- { "uint", TYPE_UINT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uint", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uint", TYPE_UINT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "bool", TYPE_BOOL, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bool", TYPE_BOOL, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "bool", TYPE_BOOL, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "bool", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- //conversion vectors
-
- { "ivec2", TYPE_IVEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec2", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec2", TYPE_IVEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec2", TYPE_IVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "vec2", TYPE_VEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec2", TYPE_VEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec2", TYPE_VEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "vec2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "uvec2", TYPE_UVEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec2", TYPE_UVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec2", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec2", TYPE_UVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "bvec2", TYPE_BVEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec2", TYPE_BVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec2", TYPE_BVEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "bvec2", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "ivec3", TYPE_IVEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec3", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec3", TYPE_IVEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "ivec3", TYPE_IVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "vec3", TYPE_VEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec3", TYPE_VEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec3", TYPE_VEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "vec3", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "uvec3", TYPE_UVEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec3", TYPE_UVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec3", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec3", TYPE_UVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "bvec3", TYPE_BVEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec3", TYPE_BVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec3", TYPE_BVEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "bvec3", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "ivec4", TYPE_IVEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "ivec4", TYPE_IVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "vec4", TYPE_VEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "vec4", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "uvec4", TYPE_UVEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "bvec4", TYPE_BVEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "bvec4", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- //conversion between matrixes
-
- { "mat2", TYPE_MAT2, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat2", TYPE_MAT2, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat3", TYPE_MAT3, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat3", TYPE_MAT3, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat4", TYPE_MAT4, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat4", TYPE_MAT4, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
-
- //builtins - trigonometry
-
- { "radians", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "radians", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "radians", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "radians", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "degrees", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "degrees", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "degrees", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "degrees", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "sin", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "sin", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "sin", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "sin", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "cos", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "cos", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "cos", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "cos", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "tan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "tan", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "tan", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "tan", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "asin", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "asin", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "asin", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "asin", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "acos", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "acos", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "acos", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "acos", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "atan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "atan", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "atan", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "atan", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "atan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "atan", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "atan", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "atan", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "sinh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "sinh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "sinh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "sinh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "cosh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "cosh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "cosh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "cosh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "tanh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "tanh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "tanh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "tanh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "asinh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "asinh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "asinh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "asinh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "acosh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "acosh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "acosh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "acosh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "atanh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "atanh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "atanh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "atanh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- //builtins - exponential
- { "pow", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "pow", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "pow", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "pow", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "log", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "log", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "log", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "log", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp2", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp2", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp2", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "log2", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "log2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "log2", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "log2", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "sqrt", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "sqrt", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "sqrt", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "sqrt", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "inversesqrt", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "inversesqrt", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "inversesqrt", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "inversesqrt", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- //builtins - common
- { "abs", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "abs", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "abs", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "abs", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "abs", TYPE_INT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "abs", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "abs", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "abs", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "sign", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "sign", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "sign", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "sign", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "sign", TYPE_INT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "sign", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "sign", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "sign", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "floor", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "floor", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "floor", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "floor", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "trunc", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "trunc", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "trunc", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "trunc", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "round", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "round", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "round", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "round", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "roundEven", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "roundEven", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "roundEven", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "roundEven", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "ceil", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ceil", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "ceil", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "ceil", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "fract", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "fract", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "fract", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "fract", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "mod", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mod", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "mod", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mod", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "mod", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mod", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "mod", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "modf", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "modf", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "modf", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "modf", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "min", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "min", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "min", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "min", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "min", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "min", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "min", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "min", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "min", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "max", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "max", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "max", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "max", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "max", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "max", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "max", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "max", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "max", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "clamp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "clamp", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "clamp", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "clamp", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "clamp", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "clamp", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "clamp", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "clamp", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "clamp", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "mix", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "step", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "step", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "step", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "step", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "step", TYPE_VEC2, { TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "step", TYPE_VEC3, { TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "step", TYPE_VEC4, { TYPE_FLOAT, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "smoothstep", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "smoothstep", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "smoothstep", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "smoothstep", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "smoothstep", TYPE_VEC2, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "smoothstep", TYPE_VEC3, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "smoothstep", TYPE_VEC4, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "isnan", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "isnan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "isnan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "isnan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "isinf", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "isinf", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "isinf", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "isinf", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "floatBitsToInt", TYPE_INT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "floatBitsToInt", TYPE_IVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "floatBitsToInt", TYPE_IVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "floatBitsToInt", TYPE_IVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "floatBitsToUint", TYPE_UINT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "floatBitsToUint", TYPE_UVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "floatBitsToUint", TYPE_UVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "floatBitsToUint", TYPE_UVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "intBitsToFloat", TYPE_FLOAT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "intBitsToFloat", TYPE_VEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "intBitsToFloat", TYPE_VEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "intBitsToFloat", TYPE_VEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "uintBitsToFloat", TYPE_FLOAT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uintBitsToFloat", TYPE_VEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "uintBitsToFloat", TYPE_VEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "uintBitsToFloat", TYPE_VEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- //builtins - geometric
- { "length", TYPE_FLOAT, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "length", TYPE_FLOAT, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "length", TYPE_FLOAT, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "distance", TYPE_FLOAT, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "distance", TYPE_FLOAT, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "distance", TYPE_FLOAT, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "dot", TYPE_FLOAT, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "dot", TYPE_FLOAT, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "dot", TYPE_FLOAT, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "cross", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "normalize", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "normalize", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "normalize", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "reflect", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "refract", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "faceforward", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "faceforward", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "faceforward", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "matrixCompMult", TYPE_MAT2, { TYPE_MAT2, TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
- { "matrixCompMult", TYPE_MAT3, { TYPE_MAT3, TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
- { "matrixCompMult", TYPE_MAT4, { TYPE_MAT4, TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "outerProduct", TYPE_MAT2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "outerProduct", TYPE_MAT3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "outerProduct", TYPE_MAT4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "transpose", TYPE_MAT2, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
- { "transpose", TYPE_MAT3, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
- { "transpose", TYPE_MAT4, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "determinant", TYPE_FLOAT, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
- { "determinant", TYPE_FLOAT, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
- { "determinant", TYPE_FLOAT, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "inverse", TYPE_MAT2, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
- { "inverse", TYPE_MAT3, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
- { "inverse", TYPE_MAT4, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "lessThan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "lessThan", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThan", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThan", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "lessThan", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "lessThan", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "lessThan", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "greaterThan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "greaterThan", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThan", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThan", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "greaterThan", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "greaterThan", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "greaterThan", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "lessThanEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThanEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThanEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "lessThanEqual", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThanEqual", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThanEqual", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "lessThanEqual", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "lessThanEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "lessThanEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "greaterThanEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThanEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThanEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "greaterThanEqual", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThanEqual", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThanEqual", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "greaterThanEqual", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "greaterThanEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "greaterThanEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "equal", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "equal", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "equal", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "equal", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "equal", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "equal", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "equal", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "equal", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "equal", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "equal", TYPE_BVEC2, { TYPE_BVEC2, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "equal", TYPE_BVEC3, { TYPE_BVEC3, TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "equal", TYPE_BVEC4, { TYPE_BVEC4, TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "notEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "notEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "notEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "notEqual", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "notEqual", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "notEqual", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "notEqual", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "notEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "notEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "notEqual", TYPE_BVEC2, { TYPE_BVEC2, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "notEqual", TYPE_BVEC3, { TYPE_BVEC3, TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "notEqual", TYPE_BVEC4, { TYPE_BVEC4, TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "any", TYPE_BOOL, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "any", TYPE_BOOL, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "any", TYPE_BOOL, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "all", TYPE_BOOL, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "all", TYPE_BOOL, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "all", TYPE_BOOL, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "not", TYPE_BVEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "not", TYPE_BVEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "not", TYPE_BVEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- //builtins - texture
- { "textureSize", TYPE_IVEC2, { TYPE_SAMPLER2D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC2, { TYPE_ISAMPLER2D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC2, { TYPE_USAMPLER2D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER2DARRAY, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER2DARRAY, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER2DARRAY, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER3D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER3D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER3D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBE, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBEARRAY, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureLod", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "dFdx", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "dFdx", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "dFdx", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "dFdx", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "dFdy", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "dFdy", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "dFdy", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "dFdy", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "fwidth", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "fwidth", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "fwidth", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "fwidth", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- //sub-functions
-
- //array
- { "length", TYPE_INT, { TYPE_VOID }, TAG_ARRAY, true },
-
- // modern functions
-
- { "fma", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "fma", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "fma", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "fma", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { nullptr, TYPE_VOID, { TYPE_VOID }, TAG_GLOBAL, false }
+ // Constructors.
+
+ { "bool", TYPE_BOOL, { TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec2", TYPE_BVEC2, { TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec2", TYPE_BVEC2, { TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec3", TYPE_BVEC3, { TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec3", TYPE_BVEC3, { TYPE_BOOL, TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec3", TYPE_BVEC3, { TYPE_BVEC2, TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec3", TYPE_BVEC3, { TYPE_BOOL, TYPE_BVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BOOL, TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BVEC2, TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BVEC2, TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BOOL, TYPE_BVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BVEC3, TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BVEC2, TYPE_BVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ { "float", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec2", TYPE_VEC2, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec2", TYPE_VEC2, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec3", TYPE_VEC3, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec3", TYPE_VEC3, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec3", TYPE_VEC3, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec3", TYPE_VEC3, { TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_VEC2, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ { "int", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec2", TYPE_IVEC2, { TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec2", TYPE_IVEC2, { TYPE_INT, TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec3", TYPE_IVEC3, { TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec3", TYPE_IVEC3, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec3", TYPE_IVEC3, { TYPE_IVEC2, TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec3", TYPE_IVEC3, { TYPE_INT, TYPE_IVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_IVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_INT, TYPE_IVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_IVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_IVEC3, TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ { "uint", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec2", TYPE_UVEC2, { TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec2", TYPE_UVEC2, { TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec3", TYPE_UVEC3, { TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec3", TYPE_UVEC3, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec3", TYPE_UVEC3, { TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec3", TYPE_UVEC3, { TYPE_UINT, TYPE_UVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UVEC2, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UINT, TYPE_UVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UVEC3, TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+
+ { "mat2", TYPE_MAT2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "mat3", TYPE_MAT3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "mat4", TYPE_MAT4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ { "mat2", TYPE_MAT2, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "mat3", TYPE_MAT3, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "mat4", TYPE_MAT4, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ // Conversion scalars.
+
+ { "int", TYPE_INT, { TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "int", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "int", TYPE_INT, { TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "int", TYPE_INT, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ { "float", TYPE_FLOAT, { TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "float", TYPE_FLOAT, { TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "float", TYPE_FLOAT, { TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "float", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ { "uint", TYPE_UINT, { TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uint", TYPE_UINT, { TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uint", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uint", TYPE_UINT, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+
+ { "bool", TYPE_BOOL, { TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bool", TYPE_BOOL, { TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bool", TYPE_BOOL, { TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "bool", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ // Conversion vectors.
+
+ { "ivec2", TYPE_IVEC2, { TYPE_BVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec2", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec2", TYPE_IVEC2, { TYPE_UVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec2", TYPE_IVEC2, { TYPE_VEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ { "vec2", TYPE_VEC2, { TYPE_BVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec2", TYPE_VEC2, { TYPE_IVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec2", TYPE_VEC2, { TYPE_UVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "vec2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ { "uvec2", TYPE_UVEC2, { TYPE_BVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec2", TYPE_UVEC2, { TYPE_IVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec2", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec2", TYPE_UVEC2, { TYPE_VEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+
+ { "bvec2", TYPE_BVEC2, { TYPE_BVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec2", TYPE_BVEC2, { TYPE_IVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec2", TYPE_BVEC2, { TYPE_UVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "bvec2", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ { "ivec3", TYPE_IVEC3, { TYPE_BVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec3", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec3", TYPE_IVEC3, { TYPE_UVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "ivec3", TYPE_IVEC3, { TYPE_VEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ { "vec3", TYPE_VEC3, { TYPE_BVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec3", TYPE_VEC3, { TYPE_IVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec3", TYPE_VEC3, { TYPE_UVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "vec3", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ { "uvec3", TYPE_UVEC3, { TYPE_BVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec3", TYPE_UVEC3, { TYPE_IVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec3", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec3", TYPE_UVEC3, { TYPE_VEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+
+ { "bvec3", TYPE_BVEC3, { TYPE_BVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec3", TYPE_BVEC3, { TYPE_IVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec3", TYPE_BVEC3, { TYPE_UVEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "bvec3", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ { "ivec4", TYPE_IVEC4, { TYPE_BVEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_UVEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "ivec4", TYPE_IVEC4, { TYPE_VEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ { "vec4", TYPE_VEC4, { TYPE_BVEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_IVEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_UVEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "vec4", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ { "uvec4", TYPE_UVEC4, { TYPE_BVEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_IVEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_VEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+
+ { "bvec4", TYPE_BVEC4, { TYPE_BVEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_IVEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_UVEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, true },
+ { "bvec4", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ // Conversion between matrixes.
+
+ { "mat2", TYPE_MAT2, { TYPE_MAT3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "mat2", TYPE_MAT2, { TYPE_MAT4, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "mat3", TYPE_MAT3, { TYPE_MAT2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "mat3", TYPE_MAT3, { TYPE_MAT4, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "mat4", TYPE_MAT4, { TYPE_MAT2, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+ { "mat4", TYPE_MAT4, { TYPE_MAT3, TYPE_VOID }, { "" }, TAG_GLOBAL, false },
+
+ // Built-ins - trigonometric functions.
+ // radians
+
+ { "radians", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "degrees" }, TAG_GLOBAL, false },
+ { "radians", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "degrees" }, TAG_GLOBAL, false },
+ { "radians", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "degrees" }, TAG_GLOBAL, false },
+ { "radians", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "degrees" }, TAG_GLOBAL, false },
+
+ // degrees
+
+ { "degrees", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "radians" }, TAG_GLOBAL, false },
+ { "degrees", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "radians" }, TAG_GLOBAL, false },
+ { "degrees", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "radians" }, TAG_GLOBAL, false },
+ { "degrees", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "radians" }, TAG_GLOBAL, false },
+
+ // sin
+
+ { "sin", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false },
+ { "sin", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false },
+ { "sin", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false },
+ { "sin", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false },
+
+ // cos
+
+ { "cos", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false },
+ { "cos", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false },
+ { "cos", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false },
+ { "cos", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false },
+
+ // tan
+
+ { "tan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false },
+ { "tan", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false },
+ { "tan", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false },
+ { "tan", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false },
+
+ // asin
+
+ { "asin", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "asin", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "asin", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "asin", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // acos
+
+ { "acos", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "acos", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "acos", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "acos", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // atan
+
+ { "atan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "y_over_x" }, TAG_GLOBAL, false },
+ { "atan", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "y_over_x" }, TAG_GLOBAL, false },
+ { "atan", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "y_over_x" }, TAG_GLOBAL, false },
+ { "atan", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "y_over_x" }, TAG_GLOBAL, false },
+ { "atan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "y", "x" }, TAG_GLOBAL, false },
+ { "atan", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "y", "x" }, TAG_GLOBAL, false },
+ { "atan", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "y", "x" }, TAG_GLOBAL, false },
+ { "atan", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "y", "x" }, TAG_GLOBAL, false },
+
+ // sinh
+
+ { "sinh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "sinh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "sinh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "sinh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // cosh
+
+ { "cosh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "cosh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "cosh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "cosh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // tanh
+
+ { "tanh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "tanh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "tanh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "tanh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // asinh
+
+ { "asinh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "asinh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "asinh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "asinh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // acosh
+
+ { "acosh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "acosh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "acosh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "acosh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // atanh
+
+ { "atanh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "atanh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "atanh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "atanh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // Builtins - exponential functions.
+ // pow
+
+ { "pow", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false },
+ { "pow", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false },
+ { "pow", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false },
+ { "pow", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false },
+
+ // exp
+
+ { "exp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "exp", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "exp", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "exp", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // log
+
+ { "log", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "log", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "log", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "log", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // exp2
+
+ { "exp2", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "exp2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "exp2", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "exp2", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // log2
+
+ { "log2", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "log2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "log2", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "log2", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // sqrt
+
+ { "sqrt", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "sqrt", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "sqrt", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "sqrt", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // inversesqrt
+
+ { "inversesqrt", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "inversesqrt", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "inversesqrt", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "inversesqrt", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // Built-ins - common functions.
+ // abs
+
+ { "abs", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "abs", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "abs", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "abs", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ { "abs", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "abs", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "abs", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "abs", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // sign
+
+ { "sign", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "sign", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "sign", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "sign", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ { "sign", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "sign", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "sign", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "sign", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // floor
+
+ { "floor", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "floor", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "floor", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "floor", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // trunc
+
+ { "trunc", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "trunc", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "trunc", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "trunc", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // round
+
+ { "round", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "round", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "round", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "round", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // roundEven
+
+ { "roundEven", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "roundEven", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "roundEven", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "roundEven", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // ceil
+
+ { "ceil", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "ceil", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "ceil", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "ceil", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // fract
+
+ { "fract", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "fract", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "fract", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "fract", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // mod
+
+ { "mod", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false },
+ { "mod", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false },
+ { "mod", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false },
+ { "mod", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false },
+ { "mod", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false },
+ { "mod", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false },
+ { "mod", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false },
+
+ // modf
+
+ { "modf", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "i" }, TAG_GLOBAL, true },
+ { "modf", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "x", "i" }, TAG_GLOBAL, true },
+ { "modf", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "x", "i" }, TAG_GLOBAL, true },
+ { "modf", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "x", "i" }, TAG_GLOBAL, true },
+
+ // min
+
+ { "min", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "min", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "min", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "min", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "min", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "min", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "min", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "min", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "min", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "min", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "min", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "min", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "min", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "min", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "min", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "min", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "min", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "min", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "min", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UINT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "min", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "min", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+
+ // max
+
+ { "max", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "max", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "max", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "max", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "max", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "max", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "max", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "max", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "max", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "max", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "max", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "max", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "max", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "max", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "max", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "max", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "max", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "max", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "max", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UINT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "max", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "max", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+
+ // clamp
+
+ { "clamp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false },
+ { "clamp", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false },
+ { "clamp", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false },
+ { "clamp", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false },
+ { "clamp", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false },
+ { "clamp", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false },
+ { "clamp", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false },
+
+ { "clamp", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false },
+ { "clamp", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false },
+ { "clamp", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false },
+ { "clamp", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false },
+ { "clamp", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false },
+ { "clamp", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false },
+ { "clamp", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false },
+
+ { "clamp", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, true },
+ { "clamp", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, true },
+ { "clamp", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, true },
+ { "clamp", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, true },
+ { "clamp", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, true },
+ { "clamp", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, true },
+ { "clamp", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, true },
+
+ // mix
+
+ { "mix", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_BVEC2, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_BVEC3, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_BVEC4, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false },
+
+ // step
+
+ { "step", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false },
+ { "step", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false },
+ { "step", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false },
+ { "step", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false },
+ { "step", TYPE_VEC2, { TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false },
+ { "step", TYPE_VEC3, { TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false },
+ { "step", TYPE_VEC4, { TYPE_FLOAT, TYPE_VEC4, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false },
+
+ // smoothstep
+
+ { "smoothstep", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false },
+ { "smoothstep", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false },
+ { "smoothstep", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false },
+ { "smoothstep", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false },
+ { "smoothstep", TYPE_VEC2, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false },
+ { "smoothstep", TYPE_VEC3, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false },
+ { "smoothstep", TYPE_VEC4, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC4, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false },
+
+ // isnan
+
+ { "isnan", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "isnan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "isnan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "isnan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // isinf
+
+ { "isinf", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "isinf", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "isinf", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "isinf", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // floatBitsToInt
+
+ { "floatBitsToInt", TYPE_INT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+ { "floatBitsToInt", TYPE_IVEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+ { "floatBitsToInt", TYPE_IVEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+ { "floatBitsToInt", TYPE_IVEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+
+ // floatBitsToUint
+
+ { "floatBitsToUint", TYPE_UINT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+ { "floatBitsToUint", TYPE_UVEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+ { "floatBitsToUint", TYPE_UVEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+ { "floatBitsToUint", TYPE_UVEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+
+ // intBitsToFloat
+
+ { "intBitsToFloat", TYPE_FLOAT, { TYPE_INT, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+ { "intBitsToFloat", TYPE_VEC2, { TYPE_IVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+ { "intBitsToFloat", TYPE_VEC3, { TYPE_IVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+ { "intBitsToFloat", TYPE_VEC4, { TYPE_IVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+
+ // uintBitsToFloat
+
+ { "uintBitsToFloat", TYPE_FLOAT, { TYPE_UINT, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+ { "uintBitsToFloat", TYPE_VEC2, { TYPE_UVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+ { "uintBitsToFloat", TYPE_VEC3, { TYPE_UVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+ { "uintBitsToFloat", TYPE_VEC4, { TYPE_UVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, true },
+
+ // Built-ins - geometric functions.
+ // length
+
+ { "length", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "length", TYPE_FLOAT, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "length", TYPE_FLOAT, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "length", TYPE_FLOAT, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // distance
+
+ { "distance", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "distance", TYPE_FLOAT, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "distance", TYPE_FLOAT, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "distance", TYPE_FLOAT, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ // dot
+
+ { "dot", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "dot", TYPE_FLOAT, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "dot", TYPE_FLOAT, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "dot", TYPE_FLOAT, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ // cross
+
+ { "cross", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ // normalize
+
+ { "normalize", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "v" }, TAG_GLOBAL, false },
+ { "normalize", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "v" }, TAG_GLOBAL, false },
+ { "normalize", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "v" }, TAG_GLOBAL, false },
+ { "normalize", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "v" }, TAG_GLOBAL, false },
+
+ // reflect
+
+ { "reflect", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "I", "N" }, TAG_GLOBAL, false },
+
+ // refract
+
+ { "refract", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "I", "N", "eta" }, TAG_GLOBAL, false },
+
+ // faceforward
+
+ { "faceforward", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "N", "I", "Nref" }, TAG_GLOBAL, false },
+ { "faceforward", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "N", "I", "Nref" }, TAG_GLOBAL, false },
+ { "faceforward", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "N", "I", "Nref" }, TAG_GLOBAL, false },
+
+ // matrixCompMult
+
+ { "matrixCompMult", TYPE_MAT2, { TYPE_MAT2, TYPE_MAT2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "matrixCompMult", TYPE_MAT3, { TYPE_MAT3, TYPE_MAT3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "matrixCompMult", TYPE_MAT4, { TYPE_MAT4, TYPE_MAT4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ // outerProduct
+
+ { "outerProduct", TYPE_MAT2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "c", "r" }, TAG_GLOBAL, false },
+ { "outerProduct", TYPE_MAT3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "c", "r" }, TAG_GLOBAL, false },
+ { "outerProduct", TYPE_MAT4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "c", "r" }, TAG_GLOBAL, false },
+
+ // transpose
+
+ { "transpose", TYPE_MAT2, { TYPE_MAT2, TYPE_VOID }, { "m" }, TAG_GLOBAL, false },
+ { "transpose", TYPE_MAT3, { TYPE_MAT3, TYPE_VOID }, { "m" }, TAG_GLOBAL, false },
+ { "transpose", TYPE_MAT4, { TYPE_MAT4, TYPE_VOID }, { "m" }, TAG_GLOBAL, false },
+
+ // determinant
+
+ { "determinant", TYPE_FLOAT, { TYPE_MAT2, TYPE_VOID }, { "m" }, TAG_GLOBAL, false },
+ { "determinant", TYPE_FLOAT, { TYPE_MAT3, TYPE_VOID }, { "m" }, TAG_GLOBAL, false },
+ { "determinant", TYPE_FLOAT, { TYPE_MAT4, TYPE_VOID }, { "m" }, TAG_GLOBAL, false },
+
+ // inverse
+
+ { "inverse", TYPE_MAT2, { TYPE_MAT2, TYPE_VOID }, { "m" }, TAG_GLOBAL, false },
+ { "inverse", TYPE_MAT3, { TYPE_MAT3, TYPE_VOID }, { "m" }, TAG_GLOBAL, false },
+ { "inverse", TYPE_MAT4, { TYPE_MAT4, TYPE_VOID }, { "m" }, TAG_GLOBAL, false },
+
+ // lessThan
+
+ { "lessThan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "lessThan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "lessThan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "lessThan", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "lessThan", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "lessThan", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "lessThan", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "lessThan", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "lessThan", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+
+ // greaterThan
+
+ { "greaterThan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "greaterThan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "greaterThan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "greaterThan", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "greaterThan", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "greaterThan", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "greaterThan", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "greaterThan", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "greaterThan", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+
+ // lessThanEqual
+
+ { "lessThanEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "lessThanEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "lessThanEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "lessThanEqual", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "lessThanEqual", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "lessThanEqual", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "lessThanEqual", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "lessThanEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "lessThanEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+
+ // greaterThanEqual
+
+ { "greaterThanEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "greaterThanEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "greaterThanEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "greaterThanEqual", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "greaterThanEqual", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "greaterThanEqual", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "greaterThanEqual", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "greaterThanEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "greaterThanEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+
+ // equal
+
+ { "equal", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "equal", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "equal", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "equal", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "equal", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "equal", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "equal", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "equal", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "equal", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+
+ { "equal", TYPE_BVEC2, { TYPE_BVEC2, TYPE_BVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "equal", TYPE_BVEC3, { TYPE_BVEC3, TYPE_BVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "equal", TYPE_BVEC4, { TYPE_BVEC4, TYPE_BVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ // notEqual
+
+ { "notEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "notEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "notEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "notEqual", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "notEqual", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "notEqual", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ { "notEqual", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "notEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+ { "notEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true },
+
+ { "notEqual", TYPE_BVEC2, { TYPE_BVEC2, TYPE_BVEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "notEqual", TYPE_BVEC3, { TYPE_BVEC3, TYPE_BVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+ { "notEqual", TYPE_BVEC4, { TYPE_BVEC4, TYPE_BVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false },
+
+ // any
+
+ { "any", TYPE_BOOL, { TYPE_BVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "any", TYPE_BOOL, { TYPE_BVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "any", TYPE_BOOL, { TYPE_BVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // all
+
+ { "all", TYPE_BOOL, { TYPE_BVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "all", TYPE_BOOL, { TYPE_BVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "all", TYPE_BOOL, { TYPE_BVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // not
+
+ { "not", TYPE_BVEC2, { TYPE_BVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "not", TYPE_BVEC3, { TYPE_BVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+ { "not", TYPE_BVEC4, { TYPE_BVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false },
+
+ // Built-ins: texture functions.
+ // textureSize
+
+ { "textureSize", TYPE_IVEC2, { TYPE_SAMPLER2D, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC2, { TYPE_ISAMPLER2D, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC2, { TYPE_USAMPLER2D, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER2DARRAY, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER2DARRAY, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER2DARRAY, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER3D, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER3D, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER3D, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBE, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBEARRAY, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true },
+
+ // texture
+
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false },
+
+ // textureProj
+
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true },
+
+ // textureLod
+
+ { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, false },
+ { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, false },
+ { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "textureLod", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, false },
+ { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, false },
+ { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, false },
+
+ // texelFetch
+
+ { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+
+ // textureProjLod
+
+ { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true },
+
+ // textureGrad
+
+ { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true },
+
+ // textureGather
+
+ { "textureGather", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureGather", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureGather", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureGather", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, true },
+ { "textureGather", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, true },
+ { "textureGather", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, true },
+ { "textureGather", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureGather", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureGather", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureGather", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, true },
+ { "textureGather", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, true },
+ { "textureGather", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, true },
+ { "textureGather", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureGather", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, true },
+
+ // dFdx
+
+ { "dFdx", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
+ { "dFdx", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
+ { "dFdx", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
+ { "dFdx", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
+
+ // dFdy
+
+ { "dFdy", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
+ { "dFdy", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
+ { "dFdy", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
+ { "dFdy", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
+
+ // fwidth
+
+ { "fwidth", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
+ { "fwidth", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
+ { "fwidth", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
+ { "fwidth", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
+
+ // Sub-functions.
+ // array
+
+ { "length", TYPE_INT, { TYPE_VOID }, { "" }, TAG_ARRAY, true },
+
+ // Modern functions.
+ // fma
+
+ { "fma", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b", "c" }, TAG_GLOBAL, false },
+ { "fma", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b", "c" }, TAG_GLOBAL, false },
+ { "fma", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b", "c" }, TAG_GLOBAL, false },
+ { "fma", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b", "c" }, TAG_GLOBAL, false },
+
+ // Packing/Unpacking functions.
+
+ { "packHalf2x16", TYPE_UINT, { TYPE_VEC2, TYPE_VOID }, { "v" }, TAG_GLOBAL, true },
+ { "packUnorm2x16", TYPE_UINT, { TYPE_VEC2, TYPE_VOID }, { "v" }, TAG_GLOBAL, true },
+ { "packSnorm2x16", TYPE_UINT, { TYPE_VEC2, TYPE_VOID }, { "v" }, TAG_GLOBAL, true },
+ { "packUnorm4x8", TYPE_UINT, { TYPE_VEC4, TYPE_VOID }, { "v" }, TAG_GLOBAL, true },
+ { "packSnorm4x8", TYPE_UINT, { TYPE_VEC4, TYPE_VOID }, { "v" }, TAG_GLOBAL, true },
+
+ { "unpackHalf2x16", TYPE_VEC2, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true },
+ { "unpackUnorm2x16", TYPE_VEC2, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true },
+ { "unpackSnorm2x16", TYPE_VEC2, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true },
+ { "unpackUnorm4x8", TYPE_VEC4, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true },
+ { "unpackSnorm4x8", TYPE_VEC4, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true },
+
+ // bitfieldExtract
+
+ { "bitfieldExtract", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true },
+ { "bitfieldExtract", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true },
+ { "bitfieldExtract", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true },
+ { "bitfieldExtract", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true },
+
+ { "bitfieldExtract", TYPE_UINT, { TYPE_UINT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true },
+ { "bitfieldExtract", TYPE_UVEC2, { TYPE_UVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true },
+ { "bitfieldExtract", TYPE_UVEC3, { TYPE_UVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true },
+ { "bitfieldExtract", TYPE_UVEC4, { TYPE_UVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true },
+
+ // bitfieldInsert
+
+ { "bitfieldInsert", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true },
+ { "bitfieldInsert", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true },
+ { "bitfieldInsert", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true },
+ { "bitfieldInsert", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true },
+
+ { "bitfieldInsert", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true },
+ { "bitfieldInsert", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true },
+ { "bitfieldInsert", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true },
+ { "bitfieldInsert", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true },
+
+ // bitfieldReverse
+
+ { "bitfieldReverse", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "bitfieldReverse", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "bitfieldReverse", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "bitfieldReverse", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+
+ { "bitfieldReverse", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "bitfieldReverse", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "bitfieldReverse", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "bitfieldReverse", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+
+ // bitCount
+
+ { "bitCount", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "bitCount", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "bitCount", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "bitCount", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+
+ { "bitCount", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "bitCount", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "bitCount", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "bitCount", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+
+ // findLSB
+
+ { "findLSB", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "findLSB", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "findLSB", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "findLSB", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+
+ { "findLSB", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "findLSB", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "findLSB", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "findLSB", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+
+ // findMSB
+
+ { "findMSB", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "findMSB", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "findMSB", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "findMSB", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+
+ { "findMSB", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "findMSB", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "findMSB", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+ { "findMSB", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true },
+
+ // umulExtended
+
+ { "umulExtended", TYPE_VOID, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true },
+ { "umulExtended", TYPE_VOID, { TYPE_UVEC2, TYPE_UVEC2, TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true },
+ { "umulExtended", TYPE_VOID, { TYPE_UVEC3, TYPE_UVEC3, TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true },
+ { "umulExtended", TYPE_VOID, { TYPE_UVEC4, TYPE_UVEC4, TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true },
+
+ // imulExtended
+
+ { "imulExtended", TYPE_VOID, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true },
+ { "imulExtended", TYPE_VOID, { TYPE_IVEC2, TYPE_IVEC2, TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true },
+ { "imulExtended", TYPE_VOID, { TYPE_IVEC3, TYPE_IVEC3, TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true },
+ { "imulExtended", TYPE_VOID, { TYPE_IVEC4, TYPE_IVEC4, TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true },
+
+ // uaddCarry
+
+ { "uaddCarry", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "y", "carry" }, TAG_GLOBAL, true },
+ { "uaddCarry", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "x", "y", "carry" }, TAG_GLOBAL, true },
+ { "uaddCarry", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "x", "y", "carry" }, TAG_GLOBAL, true },
+ { "uaddCarry", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "x", "y", "carry" }, TAG_GLOBAL, true },
+
+ // usubBorrow
+
+ { "usubBorrow", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "y", "borrow" }, TAG_GLOBAL, true },
+ { "usubBorrow", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "x", "y", "borrow" }, TAG_GLOBAL, true },
+ { "usubBorrow", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "x", "y", "borrow" }, TAG_GLOBAL, true },
+ { "usubBorrow", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "x", "y", "borrow" }, TAG_GLOBAL, true },
+
+ // ldexp
+
+ { "ldexp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_INT, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true },
+ { "ldexp", TYPE_VEC2, { TYPE_VEC2, TYPE_IVEC2, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true },
+ { "ldexp", TYPE_VEC3, { TYPE_VEC3, TYPE_IVEC3, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true },
+ { "ldexp", TYPE_VEC4, { TYPE_VEC4, TYPE_IVEC4, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true },
+
+ // frexp
+
+ { "frexp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_INT, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true },
+ { "frexp", TYPE_VEC2, { TYPE_VEC2, TYPE_IVEC2, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true },
+ { "frexp", TYPE_VEC3, { TYPE_VEC3, TYPE_IVEC3, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true },
+ { "frexp", TYPE_VEC4, { TYPE_VEC4, TYPE_IVEC4, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true },
+
+ { nullptr, TYPE_VOID, { TYPE_VOID }, { "" }, TAG_GLOBAL, false }
};
const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[] = {
- //constructors
- { "modf", 1 },
- { nullptr, 0 }
+ { "modf", { 1, -1 } },
+ { "umulExtended", { 2, 3 } },
+ { "imulExtended", { 2, 3 } },
+ { "uaddCarry", { 2, -1 } },
+ { "usubBorrow", { 2, -1 } },
+ { "ldexp", { 1, -1 } },
+ { "frexp", { 1, -1 } },
+ { nullptr, { 0, -1 } }
+};
+
+const ShaderLanguage::BuiltinFuncConstArgs ShaderLanguage::builtin_func_const_args[] = {
+ { "textureGather", 2, 0, 3 },
+ { nullptr, 0, 0, 0 }
};
bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) {
@@ -2182,6 +2659,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
Vector<DataType> args;
Vector<StringName> args2;
+ Vector<int> args3;
ERR_FAIL_COND_V(p_func->arguments[0]->type != Node::TYPE_VARIABLE, false);
@@ -2190,6 +2668,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
for (int i = 1; i < p_func->arguments.size(); i++) {
args.push_back(p_func->arguments[i]->get_datatype());
args2.push_back(p_func->arguments[i]->get_datatype_name());
+ args3.push_back(p_func->arguments[i]->get_array_size());
}
int argcount = args.size();
@@ -2236,6 +2715,13 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
failed_builtin = true;
bool fail = false;
for (int i = 0; i < argcount; i++) {
+ if (p_func->arguments[i + 1]->type == Node::TYPE_ARRAY) {
+ const ArrayNode *anode = static_cast<const ArrayNode *>(p_func->arguments[i + 1]);
+ if (anode->call_expression == nullptr && !anode->is_indexed()) {
+ fail = true;
+ break;
+ }
+ }
if (get_scalar_type(args[i]) == args[i] && p_func->arguments[i + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[i + 1]), builtin_func_defs[idx].args[i])) {
//all good, but needs implicit conversion later
} else if (args[i] != builtin_func_defs[idx].args[i]) {
@@ -2259,96 +2745,153 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
}
if (!fail) {
- //make sure its not an out argument used in the wrong way
- int outarg_idx = 0;
- while (builtin_func_out_args[outarg_idx].name) {
- if (String(name) == builtin_func_out_args[outarg_idx].name) {
- int arg_idx = builtin_func_out_args[outarg_idx].argument;
-
- if (arg_idx < argcount) {
- if (p_func->arguments[arg_idx + 1]->type != Node::TYPE_VARIABLE && p_func->arguments[arg_idx + 1]->type != Node::TYPE_MEMBER && p_func->arguments[arg_idx + 1]->type != Node::TYPE_ARRAY) {
- _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable, array or member.");
- return false;
+ {
+ int constarg_idx = 0;
+ while (builtin_func_const_args[constarg_idx].name) {
+ if (String(name) == builtin_func_const_args[constarg_idx].name) {
+ int arg = builtin_func_const_args[constarg_idx].arg + 1;
+ if (p_func->arguments.size() <= arg) {
+ break;
}
- if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_ARRAY) {
- ArrayNode *mn = static_cast<ArrayNode *>(p_func->arguments[arg_idx + 1]);
- if (mn->is_const) {
- fail = true;
- }
- } else if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_MEMBER) {
- MemberNode *mn = static_cast<MemberNode *>(p_func->arguments[arg_idx + 1]);
- if (mn->basetype_const) {
- fail = true;
+ int min = builtin_func_const_args[constarg_idx].min;
+ int max = builtin_func_const_args[constarg_idx].max;
+
+ bool error = false;
+ if (p_func->arguments[arg]->type == Node::TYPE_VARIABLE) {
+ const VariableNode *vn = (VariableNode *)p_func->arguments[arg];
+
+ bool is_const = false;
+ ConstantNode::Value value;
+ value.sint = -1;
+
+ _find_identifier(p_block, false, p_function_info, vn->name, nullptr, nullptr, &is_const, nullptr, nullptr, &value);
+ if (!is_const || value.sint < min || value.sint > max) {
+ error = true;
}
- } else { // TYPE_VARIABLE
- VariableNode *vn = static_cast<VariableNode *>(p_func->arguments[arg_idx + 1]);
- if (vn->is_const) {
- fail = true;
- } else {
- StringName varname = vn->name;
- if (shader->uniforms.has(varname)) {
- fail = true;
- } else {
- if (p_function_info.built_ins.has(varname)) {
- BuiltInInfo info = p_function_info.built_ins[varname];
- if (info.constant) {
- fail = true;
- }
+ } else {
+ if (p_func->arguments[arg]->type == Node::TYPE_CONSTANT) {
+ ConstantNode *cn = (ConstantNode *)p_func->arguments[arg];
+
+ if (cn->get_datatype() == TYPE_INT && cn->values.size() == 1) {
+ int value = cn->values[0].sint;
+
+ if (value < min || value > max) {
+ error = true;
}
+ } else {
+ error = true;
}
+ } else {
+ error = true;
}
}
- if (fail) {
- _set_error(vformat("Constant value cannot be passed for '%s' parameter!", "out"));
+ if (error) {
+ _set_error(vformat("Expected integer constant within %s..%s range.", min, max));
return false;
}
+ }
+ constarg_idx++;
+ }
+ }
- StringName var_name;
- if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_ARRAY) {
- var_name = static_cast<const ArrayNode *>(p_func->arguments[arg_idx + 1])->name;
- } else if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_MEMBER) {
- Node *n = static_cast<const MemberNode *>(p_func->arguments[arg_idx + 1])->owner;
- while (n->type == Node::TYPE_MEMBER) {
- n = static_cast<const MemberNode *>(n)->owner;
- }
- if (n->type != Node::TYPE_VARIABLE && n->type != Node::TYPE_ARRAY) {
+ //make sure its not an out argument used in the wrong way
+ int outarg_idx = 0;
+ while (builtin_func_out_args[outarg_idx].name) {
+ if (String(name) == builtin_func_out_args[outarg_idx].name) {
+ for (int arg = 0; arg < BuiltinFuncOutArgs::MAX_ARGS; arg++) {
+ int arg_idx = builtin_func_out_args[outarg_idx].arguments[arg];
+ if (arg_idx == -1) {
+ break;
+ }
+ if (arg_idx < argcount) {
+ if (p_func->arguments[arg_idx + 1]->type != Node::TYPE_VARIABLE && p_func->arguments[arg_idx + 1]->type != Node::TYPE_MEMBER && p_func->arguments[arg_idx + 1]->type != Node::TYPE_ARRAY) {
_set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable, array or member.");
return false;
}
- if (n->type == Node::TYPE_VARIABLE) {
- var_name = static_cast<const VariableNode *>(n)->name;
- } else { // TYPE_ARRAY
- var_name = static_cast<const ArrayNode *>(n)->name;
+
+ if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_ARRAY) {
+ ArrayNode *mn = static_cast<ArrayNode *>(p_func->arguments[arg_idx + 1]);
+ if (mn->is_const) {
+ fail = true;
+ }
+ } else if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_MEMBER) {
+ MemberNode *mn = static_cast<MemberNode *>(p_func->arguments[arg_idx + 1]);
+ if (mn->basetype_const) {
+ fail = true;
+ }
+ } else { // TYPE_VARIABLE
+ VariableNode *vn = static_cast<VariableNode *>(p_func->arguments[arg_idx + 1]);
+ if (vn->is_const) {
+ fail = true;
+ } else {
+ StringName varname = vn->name;
+ if (shader->uniforms.has(varname)) {
+ fail = true;
+ } else {
+ if (shader->varyings.has(varname)) {
+ _set_error(vformat("Varyings cannot be passed for '%s' parameter!", "out"));
+ return false;
+ }
+ if (p_function_info.built_ins.has(varname)) {
+ BuiltInInfo info = p_function_info.built_ins[varname];
+ if (info.constant) {
+ fail = true;
+ }
+ }
+ }
+ }
+ }
+ if (fail) {
+ _set_error(vformat("Constant value cannot be passed for '%s' parameter!", "out"));
+ return false;
}
- } else { // TYPE_VARIABLE
- var_name = static_cast<const VariableNode *>(p_func->arguments[arg_idx + 1])->name;
- }
- const BlockNode *b = p_block;
- bool valid = false;
- while (b) {
- if (b->variables.has(var_name) || p_function_info.built_ins.has(var_name)) {
- valid = true;
- break;
+
+ StringName var_name;
+ if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_ARRAY) {
+ var_name = static_cast<const ArrayNode *>(p_func->arguments[arg_idx + 1])->name;
+ } else if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_MEMBER) {
+ Node *n = static_cast<const MemberNode *>(p_func->arguments[arg_idx + 1])->owner;
+ while (n->type == Node::TYPE_MEMBER) {
+ n = static_cast<const MemberNode *>(n)->owner;
+ }
+ if (n->type != Node::TYPE_VARIABLE && n->type != Node::TYPE_ARRAY) {
+ _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable, array or member.");
+ return false;
+ }
+ if (n->type == Node::TYPE_VARIABLE) {
+ var_name = static_cast<const VariableNode *>(n)->name;
+ } else { // TYPE_ARRAY
+ var_name = static_cast<const ArrayNode *>(n)->name;
+ }
+ } else { // TYPE_VARIABLE
+ var_name = static_cast<const VariableNode *>(p_func->arguments[arg_idx + 1])->name;
}
- if (b->parent_function) {
- for (int i = 0; i < b->parent_function->arguments.size(); i++) {
- if (b->parent_function->arguments[i].name == var_name) {
- valid = true;
- break;
+ const BlockNode *b = p_block;
+ bool valid = false;
+ while (b) {
+ if (b->variables.has(var_name) || p_function_info.built_ins.has(var_name)) {
+ valid = true;
+ break;
+ }
+ if (b->parent_function) {
+ for (int i = 0; i < b->parent_function->arguments.size(); i++) {
+ if (b->parent_function->arguments[i].name == var_name) {
+ valid = true;
+ break;
+ }
}
}
+ b = b->parent_block;
}
- b = b->parent_block;
- }
- if (!valid) {
- _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' can only take a local variable, array or member.");
- return false;
+ if (!valid) {
+ _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' can only take a local variable, array or member.");
+ return false;
+ }
}
}
}
-
outarg_idx++;
}
//implicitly convert values if possible
@@ -2408,6 +2951,11 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
} else {
arg_name = get_datatype_name(args[i]);
}
+ if (args3[i] > 0) {
+ arg_name += "[";
+ arg_name += itos(args3[i]);
+ arg_name += "]";
+ }
err += arg_name;
}
err += ")";
@@ -2457,6 +3005,11 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
} else {
func_arg_name = get_datatype_name(pfunc->arguments[j].type);
}
+ if (pfunc->arguments[j].array_size > 0) {
+ func_arg_name += "[";
+ func_arg_name += itos(pfunc->arguments[j].array_size);
+ func_arg_name += "]";
+ }
arg_list += func_arg_name;
}
}
@@ -2469,21 +3022,32 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
bool fail = false;
for (int j = 0; j < args.size(); j++) {
- if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) {
+ if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::TYPE_CONSTANT && args3[j] == 0 && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) {
//all good, but it needs implicit conversion later
- } else if (args[j] != pfunc->arguments[j].type || (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].type_str)) {
+ } else if (args[j] != pfunc->arguments[j].type || (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].type_str) || args3[j] != pfunc->arguments[j].array_size) {
String func_arg_name;
if (pfunc->arguments[j].type == TYPE_STRUCT) {
func_arg_name = pfunc->arguments[j].type_str;
} else {
func_arg_name = get_datatype_name(pfunc->arguments[j].type);
}
+ if (pfunc->arguments[j].array_size > 0) {
+ func_arg_name += "[";
+ func_arg_name += itos(pfunc->arguments[j].array_size);
+ func_arg_name += "]";
+ }
String arg_name;
if (args[j] == TYPE_STRUCT) {
arg_name = args2[j];
} else {
arg_name = get_datatype_name(args[j]);
}
+ if (args3[j] > 0) {
+ arg_name += "[";
+ arg_name += itos(args3[j]);
+ arg_name += "]";
+ }
+
_set_error(vformat("Invalid argument for \"%s(%s)\" function: argument %s should be %s but is %s.", String(name), arg_list, j + 1, func_arg_name, arg_name));
fail = true;
break;
@@ -2529,16 +3093,45 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
return false;
}
-bool ShaderLanguage::_compare_datatypes_in_nodes(Node *a, Node *b) const {
- if (a->get_datatype() != b->get_datatype()) {
- return false;
+bool ShaderLanguage::_compare_datatypes(DataType p_datatype_a, String p_datatype_name_a, int p_array_size_a, DataType p_datatype_b, String p_datatype_name_b, int p_array_size_b) {
+ bool result = true;
+
+ if (p_datatype_a == TYPE_STRUCT || p_datatype_b == TYPE_STRUCT) {
+ if (p_datatype_name_a != p_datatype_name_b) {
+ result = false;
+ }
+ } else {
+ if (p_datatype_a != p_datatype_b) {
+ result = false;
+ }
}
- if (a->get_datatype() == TYPE_STRUCT || b->get_datatype() == TYPE_STRUCT) {
- if (a->get_datatype_name() != b->get_datatype_name()) {
- return false;
+
+ if (p_array_size_a != p_array_size_b) {
+ result = false;
+ }
+
+ if (!result) {
+ String type_name = p_datatype_a == TYPE_STRUCT ? p_datatype_name_a : get_datatype_name(p_datatype_a);
+ if (p_array_size_a > 0) {
+ type_name += "[";
+ type_name += itos(p_array_size_a);
+ type_name += "]";
}
+
+ String type_name2 = p_datatype_b == TYPE_STRUCT ? p_datatype_name_b : get_datatype_name(p_datatype_b);
+ if (p_array_size_b > 0) {
+ type_name2 += "[";
+ type_name2 += itos(p_array_size_b);
+ type_name2 += "]";
+ }
+
+ _set_error("Invalid assignment of '" + type_name2 + "' to '" + type_name + "'");
}
- return true;
+ return result;
+}
+
+bool ShaderLanguage::_compare_datatypes_in_nodes(Node *a, Node *b) {
+ return _compare_datatypes(a->get_datatype(), a->get_datatype_name(), a->get_array_size(), b->get_datatype(), b->get_datatype_name(), b->get_array_size());
}
bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg) {
@@ -2623,6 +3216,20 @@ bool ShaderLanguage::is_token_operator(TokenType p_type) {
p_type == TK_COLON);
}
+bool ShaderLanguage::is_token_operator_assign(TokenType p_type) {
+ return (p_type == TK_OP_ASSIGN ||
+ p_type == TK_OP_ASSIGN_ADD ||
+ p_type == TK_OP_ASSIGN_SUB ||
+ p_type == TK_OP_ASSIGN_MUL ||
+ p_type == TK_OP_ASSIGN_DIV ||
+ p_type == TK_OP_ASSIGN_MOD ||
+ p_type == TK_OP_ASSIGN_SHIFT_LEFT ||
+ p_type == TK_OP_ASSIGN_SHIFT_RIGHT ||
+ p_type == TK_OP_ASSIGN_BIT_AND ||
+ p_type == TK_OP_ASSIGN_BIT_OR ||
+ p_type == TK_OP_ASSIGN_BIT_XOR);
+}
+
bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value) {
if (p_constant->datatype == p_to_type) {
if (p_value) {
@@ -2666,100 +3273,329 @@ bool ShaderLanguage::is_scalar_type(DataType p_type) {
return p_type == TYPE_BOOL || p_type == TYPE_INT || p_type == TYPE_UINT || p_type == TYPE_FLOAT;
}
+bool ShaderLanguage::is_float_type(DataType p_type) {
+ switch (p_type) {
+ case TYPE_FLOAT:
+ case TYPE_VEC2:
+ case TYPE_VEC3:
+ case TYPE_VEC4:
+ case TYPE_MAT2:
+ case TYPE_MAT3:
+ case TYPE_MAT4:
+ case TYPE_SAMPLER2D:
+ case TYPE_SAMPLER2DARRAY:
+ case TYPE_SAMPLER3D:
+ case TYPE_SAMPLERCUBE:
+ case TYPE_SAMPLERCUBEARRAY: {
+ return true;
+ }
+ default: {
+ return false;
+ }
+ }
+}
bool ShaderLanguage::is_sampler_type(DataType p_type) {
return p_type == TYPE_SAMPLER2D ||
- p_type == TYPE_ISAMPLER2D ||
- p_type == TYPE_USAMPLER2D ||
- p_type == TYPE_SAMPLER2DARRAY ||
- p_type == TYPE_ISAMPLER2DARRAY ||
- p_type == TYPE_USAMPLER2DARRAY ||
- p_type == TYPE_SAMPLER3D ||
- p_type == TYPE_ISAMPLER3D ||
- p_type == TYPE_USAMPLER3D ||
- p_type == TYPE_SAMPLERCUBE ||
- p_type == TYPE_SAMPLERCUBEARRAY;
+ p_type == TYPE_ISAMPLER2D ||
+ p_type == TYPE_USAMPLER2D ||
+ p_type == TYPE_SAMPLER2DARRAY ||
+ p_type == TYPE_ISAMPLER2DARRAY ||
+ p_type == TYPE_USAMPLER2DARRAY ||
+ p_type == TYPE_SAMPLER3D ||
+ p_type == TYPE_ISAMPLER3D ||
+ p_type == TYPE_USAMPLER3D ||
+ p_type == TYPE_SAMPLERCUBE ||
+ p_type == TYPE_SAMPLERCUBEARRAY;
}
-Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) {
+Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) {
+ int array_size = p_array_size;
+
if (p_value.size() > 0) {
Variant value;
switch (p_type) {
case ShaderLanguage::TYPE_BOOL:
- value = Variant(p_value[0].boolean);
+ if (array_size > 0) {
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].boolean);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(p_value[0].boolean);
+ }
break;
case ShaderLanguage::TYPE_BVEC2:
+ array_size *= 2;
+
+ if (array_size > 0) {
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].boolean);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(p_value[0].boolean);
+ }
+ break;
case ShaderLanguage::TYPE_BVEC3:
+ array_size *= 3;
+
+ if (array_size > 0) {
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].boolean);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(p_value[0].boolean);
+ }
+ break;
case ShaderLanguage::TYPE_BVEC4:
+ array_size *= 4;
+
+ if (array_size > 0) {
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].boolean);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(p_value[0].boolean);
+ }
+ break;
case ShaderLanguage::TYPE_INT:
- value = Variant(p_value[0].sint);
+ if (array_size > 0) {
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].sint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(p_value[0].sint);
+ }
break;
case ShaderLanguage::TYPE_IVEC2:
- value = Variant(Vector2(p_value[0].sint, p_value[1].sint));
+ if (array_size > 0) {
+ array_size *= 2;
+
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].sint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Vector2(p_value[0].sint, p_value[1].sint));
+ }
break;
case ShaderLanguage::TYPE_IVEC3:
- value = Variant(Vector3(p_value[0].sint, p_value[1].sint, p_value[2].sint));
+ if (array_size > 0) {
+ array_size *= 3;
+
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].sint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Vector3(p_value[0].sint, p_value[1].sint, p_value[2].sint));
+ }
break;
case ShaderLanguage::TYPE_IVEC4:
- value = Variant(Plane(p_value[0].sint, p_value[1].sint, p_value[2].sint, p_value[3].sint));
+ if (array_size > 0) {
+ array_size *= 4;
+
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].sint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Plane(p_value[0].sint, p_value[1].sint, p_value[2].sint, p_value[3].sint));
+ }
break;
case ShaderLanguage::TYPE_UINT:
- value = Variant(p_value[0].uint);
+ if (array_size > 0) {
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].uint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(p_value[0].uint);
+ }
break;
case ShaderLanguage::TYPE_UVEC2:
- value = Variant(Vector2(p_value[0].uint, p_value[1].uint));
+ if (array_size > 0) {
+ array_size *= 2;
+
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].uint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Vector2(p_value[0].uint, p_value[1].uint));
+ }
break;
case ShaderLanguage::TYPE_UVEC3:
- value = Variant(Vector3(p_value[0].uint, p_value[1].uint, p_value[2].uint));
+ if (array_size > 0) {
+ array_size *= 3;
+
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].uint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Vector3(p_value[0].uint, p_value[1].uint, p_value[2].uint));
+ }
break;
case ShaderLanguage::TYPE_UVEC4:
- value = Variant(Plane(p_value[0].uint, p_value[1].uint, p_value[2].uint, p_value[3].uint));
+ if (array_size > 0) {
+ array_size *= 4;
+
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].uint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Plane(p_value[0].uint, p_value[1].uint, p_value[2].uint, p_value[3].uint));
+ }
break;
case ShaderLanguage::TYPE_FLOAT:
- value = Variant(p_value[0].real);
+ if (array_size > 0) {
+ PackedFloat32Array array = PackedFloat32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].real);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(p_value[0].real);
+ }
break;
case ShaderLanguage::TYPE_VEC2:
- value = Variant(Vector2(p_value[0].real, p_value[1].real));
+ if (array_size > 0) {
+ array_size *= 2;
+
+ PackedVector2Array array = PackedVector2Array();
+ for (int i = 0; i < array_size; i += 2) {
+ array.push_back(Vector2(p_value[i].real, p_value[i + 1].real));
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Vector2(p_value[0].real, p_value[1].real));
+ }
break;
case ShaderLanguage::TYPE_VEC3:
- value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real));
+ if (array_size > 0) {
+ array_size *= 3;
+
+ PackedVector3Array array = PackedVector3Array();
+ for (int i = 0; i < array_size; i += 3) {
+ array.push_back(Vector3(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real));
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real));
+ }
break;
case ShaderLanguage::TYPE_VEC4:
- if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
- value = Variant(Color(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
+ if (array_size > 0) {
+ array_size *= 4;
+
+ if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ PackedColorArray array = PackedColorArray();
+ for (int i = 0; i < array_size; i += 4) {
+ array.push_back(Color(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real, p_value[i + 3].real));
+ }
+ value = Variant(array);
+ } else {
+ PackedFloat32Array array = PackedFloat32Array();
+ for (int i = 0; i < array_size; i += 4) {
+ array.push_back(p_value[i].real);
+ array.push_back(p_value[i + 1].real);
+ array.push_back(p_value[i + 2].real);
+ array.push_back(p_value[i + 3].real);
+ }
+ value = Variant(array);
+ }
} else {
- value = Variant(Plane(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
+ if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ value = Variant(Color(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
+ } else {
+ value = Variant(Plane(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
+ }
}
break;
case ShaderLanguage::TYPE_MAT2:
- value = Variant(Transform2D(p_value[0].real, p_value[2].real, p_value[1].real, p_value[3].real, 0.0, 0.0));
+ if (array_size > 0) {
+ array_size *= 4;
+
+ PackedFloat32Array array = PackedFloat32Array();
+ for (int i = 0; i < array_size; i += 4) {
+ array.push_back(p_value[i].real);
+ array.push_back(p_value[i + 1].real);
+ array.push_back(p_value[i + 2].real);
+ array.push_back(p_value[i + 3].real);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Transform2D(p_value[0].real, p_value[2].real, p_value[1].real, p_value[3].real, 0.0, 0.0));
+ }
break;
case ShaderLanguage::TYPE_MAT3: {
- Basis p;
- p[0][0] = p_value[0].real;
- p[0][1] = p_value[1].real;
- p[0][2] = p_value[2].real;
- p[1][0] = p_value[3].real;
- p[1][1] = p_value[4].real;
- p[1][2] = p_value[5].real;
- p[2][0] = p_value[6].real;
- p[2][1] = p_value[7].real;
- p[2][2] = p_value[8].real;
- value = Variant(p);
+ if (array_size > 0) {
+ array_size *= 9;
+
+ PackedFloat32Array array = PackedFloat32Array();
+ for (int i = 0; i < array_size; i += 9) {
+ for (int j = 0; j < 9; j++) {
+ array.push_back(p_value[i + j].real);
+ }
+ }
+ value = Variant(array);
+ } else {
+ Basis p;
+ p[0][0] = p_value[0].real;
+ p[0][1] = p_value[1].real;
+ p[0][2] = p_value[2].real;
+ p[1][0] = p_value[3].real;
+ p[1][1] = p_value[4].real;
+ p[1][2] = p_value[5].real;
+ p[2][0] = p_value[6].real;
+ p[2][1] = p_value[7].real;
+ p[2][2] = p_value[8].real;
+ value = Variant(p);
+ }
break;
}
case ShaderLanguage::TYPE_MAT4: {
- Basis p;
- p[0][0] = p_value[0].real;
- p[0][1] = p_value[1].real;
- p[0][2] = p_value[2].real;
- p[1][0] = p_value[4].real;
- p[1][1] = p_value[5].real;
- p[1][2] = p_value[6].real;
- p[2][0] = p_value[8].real;
- p[2][1] = p_value[9].real;
- p[2][2] = p_value[10].real;
- Transform t = Transform(p, Vector3(p_value[3].real, p_value[7].real, p_value[11].real));
- value = Variant(t);
+ if (array_size > 0) {
+ array_size *= 16;
+
+ PackedFloat32Array array = PackedFloat32Array();
+ for (int i = 0; i < array_size; i += 16) {
+ for (int j = 0; j < 16; j++) {
+ array.push_back(p_value[i + j].real);
+ }
+ }
+ value = Variant(array);
+ } else {
+ Basis p;
+ p[0][0] = p_value[0].real;
+ p[0][1] = p_value[1].real;
+ p[0][2] = p_value[2].real;
+ p[1][0] = p_value[4].real;
+ p[1][1] = p_value[5].real;
+ p[1][2] = p_value[6].real;
+ p[2][0] = p_value[8].real;
+ p[2][1] = p_value[9].real;
+ p[2][2] = p_value[10].real;
+ Transform3D t = Transform3D(p, Vector3(p_value[3].real, p_value[7].real, p_value[11].real));
+ value = Variant(t);
+ }
break;
}
case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
@@ -2795,31 +3631,50 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform
pi.type = Variant::NIL;
break;
case ShaderLanguage::TYPE_BOOL:
- pi.type = Variant::BOOL;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_INT32_ARRAY;
+ } else {
+ pi.type = Variant::BOOL;
+ }
break;
case ShaderLanguage::TYPE_BVEC2:
- pi.type = Variant::INT;
- pi.hint = PROPERTY_HINT_FLAGS;
- pi.hint_string = "x,y";
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_INT32_ARRAY;
+ } else {
+ pi.type = Variant::INT;
+ pi.hint = PROPERTY_HINT_FLAGS;
+ pi.hint_string = "x,y";
+ }
break;
case ShaderLanguage::TYPE_BVEC3:
- pi.type = Variant::INT;
- pi.hint = PROPERTY_HINT_FLAGS;
- pi.hint_string = "x,y,z";
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_INT32_ARRAY;
+ } else {
+ pi.type = Variant::INT;
+ pi.hint = PROPERTY_HINT_FLAGS;
+ pi.hint_string = "x,y,z";
+ }
break;
case ShaderLanguage::TYPE_BVEC4:
- pi.type = Variant::INT;
- pi.hint = PROPERTY_HINT_FLAGS;
- pi.hint_string = "x,y,z,w";
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_INT32_ARRAY;
+ } else {
+ pi.type = Variant::INT;
+ pi.hint = PROPERTY_HINT_FLAGS;
+ pi.hint_string = "x,y,z,w";
+ }
break;
case ShaderLanguage::TYPE_UINT:
case ShaderLanguage::TYPE_INT: {
- pi.type = Variant::INT;
- if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
- pi.hint = PROPERTY_HINT_RANGE;
- pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]);
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_INT32_ARRAY;
+ } else {
+ pi.type = Variant::INT;
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
+ pi.hint = PROPERTY_HINT_RANGE;
+ pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]);
+ }
}
-
} break;
case ShaderLanguage::TYPE_IVEC2:
case ShaderLanguage::TYPE_IVEC3:
@@ -2830,59 +3685,106 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform
pi.type = Variant::PACKED_INT32_ARRAY;
} break;
case ShaderLanguage::TYPE_FLOAT: {
- pi.type = Variant::FLOAT;
- if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
- pi.hint = PROPERTY_HINT_RANGE;
- pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]);
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_FLOAT32_ARRAY;
+ } else {
+ pi.type = Variant::FLOAT;
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
+ pi.hint = PROPERTY_HINT_RANGE;
+ pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]);
+ }
}
-
} break;
case ShaderLanguage::TYPE_VEC2:
- pi.type = Variant::VECTOR2;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_VECTOR2_ARRAY;
+ } else {
+ pi.type = Variant::VECTOR2;
+ }
break;
case ShaderLanguage::TYPE_VEC3:
- pi.type = Variant::VECTOR3;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_VECTOR3_ARRAY;
+ } else {
+ pi.type = Variant::VECTOR3;
+ }
break;
case ShaderLanguage::TYPE_VEC4: {
- if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
- pi.type = Variant::COLOR;
+ if (p_uniform.array_size > 0) {
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ pi.type = Variant::PACKED_COLOR_ARRAY;
+ } else {
+ pi.type = Variant::PACKED_FLOAT32_ARRAY;
+ }
} else {
- pi.type = Variant::PLANE;
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ pi.type = Variant::COLOR;
+ } else {
+ pi.type = Variant::PLANE;
+ }
}
} break;
case ShaderLanguage::TYPE_MAT2:
- pi.type = Variant::TRANSFORM2D;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_FLOAT32_ARRAY;
+ } else {
+ pi.type = Variant::TRANSFORM2D;
+ }
break;
case ShaderLanguage::TYPE_MAT3:
- pi.type = Variant::BASIS;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_FLOAT32_ARRAY;
+ } else {
+ pi.type = Variant::BASIS;
+ }
break;
case ShaderLanguage::TYPE_MAT4:
- pi.type = Variant::TRANSFORM;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_FLOAT32_ARRAY;
+ } else {
+ pi.type = Variant::TRANSFORM3D;
+ }
break;
case ShaderLanguage::TYPE_SAMPLER2D:
case ShaderLanguage::TYPE_ISAMPLER2D:
case ShaderLanguage::TYPE_USAMPLER2D: {
- pi.type = Variant::OBJECT;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::ARRAY;
+ } else {
+ pi.type = Variant::OBJECT;
+ }
pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
pi.hint_string = "Texture2D";
} break;
case ShaderLanguage::TYPE_SAMPLER2DARRAY:
case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
case ShaderLanguage::TYPE_USAMPLER2DARRAY: {
- pi.type = Variant::OBJECT;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::ARRAY;
+ } else {
+ pi.type = Variant::OBJECT;
+ }
pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
pi.hint_string = "TextureLayered";
} break;
case ShaderLanguage::TYPE_SAMPLER3D:
case ShaderLanguage::TYPE_ISAMPLER3D:
case ShaderLanguage::TYPE_USAMPLER3D: {
- pi.type = Variant::OBJECT;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::ARRAY;
+ } else {
+ pi.type = Variant::OBJECT;
+ }
pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
pi.hint_string = "Texture3D";
} break;
case ShaderLanguage::TYPE_SAMPLERCUBE:
case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: {
- pi.type = Variant::OBJECT;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::ARRAY;
+ } else {
+ pi.type = Variant::OBJECT;
+ }
pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
pi.hint_string = "TextureLayered";
} break;
@@ -2971,16 +3873,16 @@ void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
bool ShaderLanguage::is_control_flow_keyword(String p_keyword) {
return p_keyword == "break" ||
- p_keyword == "case" ||
- p_keyword == "continue" ||
- p_keyword == "default" ||
- p_keyword == "do" ||
- p_keyword == "else" ||
- p_keyword == "for" ||
- p_keyword == "if" ||
- p_keyword == "return" ||
- p_keyword == "switch" ||
- p_keyword == "while";
+ p_keyword == "case" ||
+ p_keyword == "continue" ||
+ p_keyword == "default" ||
+ p_keyword == "do" ||
+ p_keyword == "else" ||
+ p_keyword == "for" ||
+ p_keyword == "if" ||
+ p_keyword == "return" ||
+ p_keyword == "switch" ||
+ p_keyword == "while";
}
void ShaderLanguage::get_builtin_funcs(List<String> *r_keywords) {
@@ -3117,8 +4019,8 @@ bool ShaderLanguage::_is_operator_assign(Operator p_op) const {
}
bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message) {
- if (current_function == String("light")) {
- *r_message = RTR("Varying may not be assigned in the 'light' function.");
+ if (current_function != String("vertex") && current_function != String("fragment")) {
+ *r_message = vformat(RTR("Varying may not be assigned in the '%s' function."), current_function);
return false;
}
switch (p_varying.stage) {
@@ -3129,12 +4031,14 @@ bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, St
p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT;
}
break;
+ case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT:
case ShaderNode::Varying::STAGE_VERTEX:
if (current_function == varying_function_names.fragment) {
*r_message = RTR("Varyings which assigned in 'vertex' function may not be reassigned in 'fragment' or 'light'.");
return false;
}
break;
+ case ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT:
case ShaderNode::Varying::STAGE_FRAGMENT:
if (current_function == varying_function_names.vertex) {
*r_message = RTR("Varyings which assigned in 'fragment' function may not be reassigned in 'vertex' or 'light'.");
@@ -3150,13 +4054,14 @@ bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, St
bool ShaderLanguage::_validate_varying_using(ShaderNode::Varying &p_varying, String *r_message) {
switch (p_varying.stage) {
case ShaderNode::Varying::STAGE_UNKNOWN:
- *r_message = RTR("Varying must be assigned before using!");
- return false;
+ VaryingUsage usage;
+ usage.var = &p_varying;
+ usage.line = tk_line;
+ unknown_varying_usages.push_back(usage);
+ break;
case ShaderNode::Varying::STAGE_VERTEX:
- if (current_function == varying_function_names.fragment) {
- p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT;
- } else if (current_function == varying_function_names.light) {
- p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT;
+ if (current_function == varying_function_names.fragment || current_function == varying_function_names.light) {
+ p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT;
}
break;
case ShaderNode::Varying::STAGE_FRAGMENT:
@@ -3164,29 +4069,30 @@ bool ShaderLanguage::_validate_varying_using(ShaderNode::Varying &p_varying, Str
p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT;
}
break;
- case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT:
- if (current_function == varying_function_names.light) {
- *r_message = RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'");
- return false;
- }
- break;
- case ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT:
- if (current_function == varying_function_names.fragment) {
- *r_message = RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'");
- return false;
- }
- break;
default:
break;
}
return true;
}
+bool ShaderLanguage::_check_varying_usages(int *r_error_line, String *r_error_message) const {
+ for (const List<ShaderLanguage::VaryingUsage>::Element *E = unknown_varying_usages.front(); E; E = E->next()) {
+ ShaderNode::Varying::Stage stage = E->get().var->stage;
+ if (stage != ShaderNode::Varying::STAGE_UNKNOWN && stage != ShaderNode::Varying::STAGE_VERTEX && stage != ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT) {
+ *r_error_line = E->get().line;
+ *r_error_message = RTR("Fragment-stage varying could not been accessed in custom function!");
+ return false;
+ }
+ }
+
+ return true;
+}
+
bool ShaderLanguage::_check_node_constness(const Node *p_node) const {
switch (p_node->type) {
case Node::TYPE_OPERATOR: {
OperatorNode *op_node = (OperatorNode *)p_node;
- for (int i = (1 ? op_node->op == OP_CALL : 0); i < op_node->arguments.size(); i++) {
+ for (int i = int(op_node->op == OP_CALL); i < op_node->arguments.size(); i++) {
if (!_check_node_constness(op_node->arguments[i])) {
return false;
}
@@ -3301,9 +4207,9 @@ bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringNam
arg->tex_argument_check = true;
arg->tex_argument_filter = p_filter;
arg->tex_argument_repeat = p_repeat;
- for (Map<StringName, Set<int>>::Element *E = arg->tex_argument_connect.front(); E; E = E->next()) {
- for (Set<int>::Element *F = E->get().front(); F; F = F->next()) {
- if (!_propagate_function_call_sampler_uniform_settings(E->key(), F->get(), p_filter, p_repeat)) {
+ for (KeyValue<StringName, Set<int>> &E : arg->tex_argument_connect) {
+ for (Set<int>::Element *F = E.value.front(); F; F = F->next()) {
+ if (!_propagate_function_call_sampler_uniform_settings(E.key, F->get(), p_filter, p_repeat)) {
return false;
}
}
@@ -3335,9 +4241,9 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa
arg->tex_builtin_check = true;
arg->tex_builtin = p_builtin;
- for (Map<StringName, Set<int>>::Element *E = arg->tex_argument_connect.front(); E; E = E->next()) {
- for (Set<int>::Element *F = E->get().front(); F; F = F->next()) {
- if (!_propagate_function_call_sampler_builtin_reference(E->key(), F->get(), p_builtin)) {
+ for (KeyValue<StringName, Set<int>> &E : arg->tex_argument_connect) {
+ for (Set<int>::Element *F = E.value.front(); F; F = F->next()) {
+ if (!_propagate_function_call_sampler_builtin_reference(E.key, F->get(), p_builtin)) {
return false;
}
}
@@ -3349,11 +4255,122 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa
ERR_FAIL_V(false); //bug? function not found
}
-ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size) {
+ShaderLanguage::Node *ShaderLanguage::_parse_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, int &r_array_size) {
+ int array_size = 0;
+
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
+ if (n) {
+ if (n->type == Node::TYPE_VARIABLE) {
+ VariableNode *vn = static_cast<VariableNode *>(n);
+ if (vn) {
+ ConstantNode::Value v;
+ DataType data_type;
+ bool is_const = false;
+
+ _find_identifier(p_block, false, p_function_info, vn->name, &data_type, nullptr, &is_const, nullptr, nullptr, &v);
+
+ if (is_const) {
+ if (data_type == TYPE_INT) {
+ int32_t value = v.sint;
+ if (value > 0) {
+ array_size = value;
+ }
+ } else if (data_type == TYPE_UINT) {
+ uint32_t value = v.uint;
+ if (value > 0U) {
+ array_size = value;
+ }
+ }
+ }
+ }
+ } else if (n->type == Node::TYPE_OPERATOR) {
+ _set_error("Array size expressions are not yet implemented.");
+ return nullptr;
+ }
+ }
+
+ r_array_size = array_size;
+ return n;
+}
+
+Error ShaderLanguage::_parse_global_array_size(int &r_array_size) {
+ if (r_array_size > 0) {
+ _set_error("Array size is already defined!");
+ return ERR_PARSE_ERROR;
+ }
+ TkPos pos = _get_tkpos();
+ Token tk = _get_token();
+
+ int array_size = 0;
+
+ if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) {
+ _set_tkpos(pos);
+ Node *n = _parse_array_size(nullptr, FunctionInfo(), array_size);
+ if (!n) {
+ return ERR_PARSE_ERROR;
+ }
+ } else if (((int)tk.constant) > 0) {
+ array_size = (uint32_t)tk.constant;
+ }
+
+ if (array_size <= 0) {
+ _set_error("Expected single integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+
+ r_array_size = array_size;
+ return OK;
+}
+
+Error ShaderLanguage::_parse_local_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, ArrayDeclarationNode *p_node, ArrayDeclarationNode::Declaration *p_decl, int &r_array_size, bool &r_is_unknown_size) {
+ TkPos pos = _get_tkpos();
+ Token tk = _get_token();
+
+ if (tk.type == TK_BRACKET_CLOSE) {
+ r_is_unknown_size = true;
+ } else {
+ if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) {
+ _set_tkpos(pos);
+ int array_size = 0;
+ Node *n = _parse_array_size(p_block, p_function_info, array_size);
+ if (!n) {
+ return ERR_PARSE_ERROR;
+ }
+ p_decl->size = array_size;
+ p_node->size_expression = n;
+ } else if (((int)tk.constant) > 0) {
+ p_decl->size = (uint32_t)tk.constant;
+ }
+
+ if (p_decl->size <= 0) {
+ _set_error("Expected single integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+
+ r_array_size = p_decl->size;
+ }
+
+ return OK;
+}
+
+ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info) {
DataType type = TYPE_VOID;
String struct_name = "";
int array_size = 0;
bool auto_size = false;
+ bool undefined_size = false;
Token tk = _get_token();
if (tk.type == TK_CURLY_BRACKET_OPEN) {
@@ -3374,6 +4391,135 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc
TkPos pos = _get_tkpos();
tk = _get_token();
if (tk.type == TK_BRACKET_CLOSE) {
+ undefined_size = true;
+ tk = _get_token();
+ } else {
+ _set_tkpos(pos);
+
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
+ if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
+ _set_error("Expected single integer constant > 0");
+ return nullptr;
+ }
+
+ ConstantNode *cnode = (ConstantNode *)n;
+ if (cnode->values.size() == 1) {
+ array_size = cnode->values[0].sint;
+ if (array_size <= 0) {
+ _set_error("Expected single integer constant > 0");
+ return nullptr;
+ }
+ } else {
+ _set_error("Expected single integer constant > 0");
+ return nullptr;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return nullptr;
+ } else {
+ tk = _get_token();
+ }
+ }
+ } else {
+ _set_error("Expected '['");
+ return nullptr;
+ }
+ }
+
+ ArrayConstructNode *an = alloc_node<ArrayConstructNode>();
+
+ if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization
+ int idx = 0;
+ while (true) {
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
+ if (!n) {
+ return nullptr;
+ }
+
+ // define type by using the first member
+ if (auto_size && idx == 0) {
+ type = n->get_datatype();
+ if (type == TYPE_STRUCT) {
+ struct_name = n->get_datatype_name();
+ }
+ } else {
+ if (!_compare_datatypes(type, struct_name, 0, n->get_datatype(), n->get_datatype_name(), 0)) {
+ return nullptr;
+ }
+ }
+
+ tk = _get_token();
+ if (tk.type == TK_COMMA) {
+ an->initializer.push_back(n);
+ } else if (!auto_size && tk.type == TK_PARENTHESIS_CLOSE) {
+ an->initializer.push_back(n);
+ break;
+ } else if (auto_size && tk.type == TK_CURLY_BRACKET_CLOSE) {
+ an->initializer.push_back(n);
+ break;
+ } else {
+ if (auto_size) {
+ _set_error("Expected '}' or ','");
+ } else {
+ _set_error("Expected ')' or ','");
+ }
+ return nullptr;
+ }
+ idx++;
+ }
+ if (!auto_size && !undefined_size && an->initializer.size() != array_size) {
+ _set_error("Array size mismatch");
+ return nullptr;
+ }
+ } else {
+ _set_error("Expected array initialization!");
+ return nullptr;
+ }
+
+ an->datatype = type;
+ an->struct_name = struct_name;
+ return an;
+}
+
+ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size) {
+ DataType type = TYPE_VOID;
+ String struct_name = "";
+ int array_size = 0;
+ bool auto_size = false;
+ TkPos prev_pos = _get_tkpos();
+ Token tk = _get_token();
+
+ if (tk.type == TK_CURLY_BRACKET_OPEN) {
+ auto_size = true;
+ } else {
+ if (shader->structs.has(tk.text)) {
+ type = TYPE_STRUCT;
+ struct_name = tk.text;
+ } else {
+ if (!is_token_variable_datatype(tk.type)) {
+ _set_tkpos(prev_pos);
+
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
+
+ if (!n) {
+ _set_error("Invalid data type for array");
+ return nullptr;
+ }
+
+ if (!_compare_datatypes(p_type, p_struct_name, p_array_size, n->get_datatype(), n->get_datatype_name(), n->get_array_size())) {
+ return nullptr;
+ }
+ return n;
+ }
+ type = get_token_datatype(tk.type);
+ }
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_OPEN) {
+ TkPos pos = _get_tkpos();
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_CLOSE) {
array_size = p_array_size;
tk = _get_token();
} else {
@@ -3445,8 +4591,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc
return nullptr;
}
- if (p_type != n->get_datatype() || p_struct_name != n->get_datatype_name()) {
- _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (type == TYPE_STRUCT ? struct_name : get_datatype_name(type)) + "'");
+ if (!_compare_datatypes(p_type, p_struct_name, 0, n->get_datatype(), n->get_datatype_name(), n->get_array_size())) {
return nullptr;
}
@@ -3546,50 +4691,73 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
//make sure void is not used in expression
_set_error("Void value not allowed in Expression");
return nullptr;
- } else if (is_token_nonvoid_datatype(tk.type)) {
- //basic type constructor
+ } else if (is_token_nonvoid_datatype(tk.type) || tk.type == TK_CURLY_BRACKET_OPEN) {
+ if (tk.type == TK_CURLY_BRACKET_OPEN) {
+ //array constructor
- OperatorNode *func = alloc_node<OperatorNode>();
- func->op = OP_CONSTRUCT;
+ _set_tkpos(prepos);
+ expr = _parse_array_constructor(p_block, p_function_info);
+ } else {
+ DataType datatype;
+ DataPrecision precision;
+ bool precision_defined = false;
- if (is_token_precision(tk.type)) {
- func->return_precision_cache = get_token_precision(tk.type);
+ if (is_token_precision(tk.type)) {
+ precision = get_token_precision(tk.type);
+ precision_defined = true;
+ tk = _get_token();
+ }
+
+ datatype = get_token_datatype(tk.type);
tk = _get_token();
- }
- VariableNode *funcname = alloc_node<VariableNode>();
- funcname->name = get_datatype_name(get_token_datatype(tk.type));
- func->arguments.push_back(funcname);
+ if (tk.type == TK_BRACKET_OPEN) {
+ //array constructor
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after type name");
- return nullptr;
- }
+ _set_tkpos(prepos);
+ expr = _parse_array_constructor(p_block, p_function_info);
+ } else {
+ if (tk.type != TK_PARENTHESIS_OPEN) {
+ _set_error("Expected '(' after type name");
+ return nullptr;
+ }
+ //basic type constructor
- int carg = -1;
+ OperatorNode *func = alloc_node<OperatorNode>();
+ func->op = OP_CONSTRUCT;
- bool ok = _parse_function_arguments(p_block, p_function_info, func, &carg);
+ if (precision_defined) {
+ func->return_precision_cache = precision;
+ }
- if (carg >= 0) {
- completion_type = COMPLETION_CALL_ARGUMENTS;
- completion_line = tk_line;
- completion_block = p_block;
- completion_function = funcname->name;
- completion_argument = carg;
- }
+ VariableNode *funcname = alloc_node<VariableNode>();
+ funcname->name = get_datatype_name(datatype);
+ func->arguments.push_back(funcname);
- if (!ok) {
- return nullptr;
- }
+ int carg = -1;
- if (!_validate_function_call(p_block, p_function_info, func, &func->return_cache, &func->struct_name)) {
- _set_error("No matching constructor found for: '" + String(funcname->name) + "'");
- return nullptr;
- }
+ bool ok = _parse_function_arguments(p_block, p_function_info, func, &carg);
- expr = _reduce_expression(p_block, func);
+ if (carg >= 0) {
+ completion_type = COMPLETION_CALL_ARGUMENTS;
+ completion_line = tk_line;
+ completion_block = p_block;
+ completion_function = funcname->name;
+ completion_argument = carg;
+ }
+ if (!ok) {
+ return nullptr;
+ }
+
+ if (!_validate_function_call(p_block, p_function_info, func, &func->return_cache, &func->struct_name)) {
+ _set_error("No matching constructor found for: '" + String(funcname->name) + "'");
+ return nullptr;
+ }
+
+ expr = _reduce_expression(p_block, func);
+ }
+ }
} else if (tk.type == TK_IDENTIFIER) {
_set_tkpos(prepos);
@@ -3602,6 +4770,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (shader->structs.has(identifier)) {
pstruct = shader->structs[identifier].shader_struct;
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_STRUCT_FLAG) && used_structs.has(identifier)) {
+ used_structs[identifier].used = true;
+ }
+#endif // DEBUG_ENABLED
struct_init = true;
}
@@ -3632,11 +4805,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (!nexpr) {
return nullptr;
}
- Node *node = pstruct->members[i];
if (!_compare_datatypes_in_nodes(pstruct->members[i], nexpr)) {
- String type_name = nexpr->get_datatype() == TYPE_STRUCT ? nexpr->get_datatype_name() : get_datatype_name(nexpr->get_datatype());
- String type_name2 = node->get_datatype() == TYPE_STRUCT ? node->get_datatype_name() : get_datatype_name(node->get_datatype());
- _set_error("Invalid assignment of '" + type_name + "' to '" + type_name2 + "'");
return nullptr;
}
}
@@ -3658,7 +4827,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expr = func;
- } else { //a function
+ } else { //a function call
const StringName &name = identifier;
@@ -3723,6 +4892,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
FunctionNode *call_function = shader->functions[function_index].function;
if (call_function) {
+ func->return_cache = call_function->get_datatype();
+ func->struct_name = call_function->get_datatype_name();
+ func->return_array_size = call_function->get_array_size();
+
//get current base function
FunctionNode *base_function = nullptr;
{
@@ -3747,7 +4920,9 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
bool error = false;
Node *n = func->arguments[argidx];
if (n->type == Node::TYPE_CONSTANT || n->type == Node::TYPE_OPERATOR) {
- error = true;
+ if (!call_function->arguments[i].is_const) {
+ error = true;
+ }
} else if (n->type == Node::TYPE_ARRAY) {
ArrayNode *an = static_cast<ArrayNode *>(n);
if (an->call_expression != nullptr || an->is_const) {
@@ -3764,6 +4939,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else if (shader->uniforms.has(varname)) {
error = true;
} else {
+ if (shader->varyings.has(varname)) {
+ _set_error(vformat("Varyings cannot be passed for '%s' parameter!", _get_qualifier_str(call_function->arguments[i].qualifier)));
+ return nullptr;
+ }
if (p_function_info.built_ins.has(varname)) {
BuiltInInfo info = p_function_info.built_ins[varname];
if (info.constant) {
@@ -3825,17 +5004,30 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
}
expr = func;
+#ifdef DEBUG_ENABLED
+ if (check_warnings) {
+ StringName func_name;
+
+ if (p_block && p_block->parent_function) {
+ func_name = p_block->parent_function->name;
+ }
+
+ _parse_used_identifier(name, IdentifierType::IDENTIFIER_FUNCTION, func_name);
+ }
+#endif // DEBUG_ENABLED
}
} else {
//an identifier
- last_const = false;
+ last_name = identifier;
+ last_type = IDENTIFIER_MAX;
_set_tkpos(pos);
DataType data_type;
IdentifierType ident_type;
int array_size = 0;
StringName struct_name;
+ bool is_local = false;
if (p_block && p_block->block_tag != SubClassTag::TAG_GLOBAL) {
int idx = 0;
@@ -3860,9 +5052,17 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (ident_type == IDENTIFIER_VARYING) {
TkPos prev_pos = _get_tkpos();
Token next_token = _get_token();
+
+ // An array of varyings.
+ if (next_token.type == TK_BRACKET_OPEN) {
+ _get_token(); // Pass constant.
+ _get_token(); // Pass TK_BRACKET_CLOSE.
+ next_token = _get_token();
+ }
_set_tkpos(prev_pos);
+
String error;
- if (next_token.type == TK_OP_ASSIGN) {
+ if (is_token_operator_assign(next_token.type)) {
if (!_validate_varying_assign(shader->varyings[identifier], &error)) {
_set_error(error);
return nullptr;
@@ -3874,12 +5074,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
}
}
- last_const = is_const;
if (ident_type == IDENTIFIER_FUNCTION) {
_set_error("Can't use function as identifier: " + String(identifier));
return nullptr;
}
+ if (is_const) {
+ last_type = IDENTIFIER_CONSTANT;
+ } else {
+ last_type = ident_type;
+ }
+
+ is_local = ident_type == IDENTIFIER_LOCAL_VAR || ident_type == IDENTIFIER_FUNCTION_ARGUMENT;
}
Node *index_expression = nullptr;
@@ -3887,13 +5093,9 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
Node *assign_expression = nullptr;
if (array_size > 0) {
+ prepos = _get_tkpos();
tk = _get_token();
- if (tk.type != TK_BRACKET_OPEN && tk.type != TK_PERIOD && tk.type != TK_OP_ASSIGN) {
- _set_error("Expected '[','.' or '='");
- return nullptr;
- }
-
if (tk.type == TK_OP_ASSIGN) {
if (is_const) {
_set_error("Constants cannot be modified.");
@@ -3912,15 +5114,14 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
data_type = call_expression->get_datatype();
- } else { // indexing
-
+ } else if (tk.type == TK_BRACKET_OPEN) { // indexing
index_expression = _parse_and_reduce_expression(p_block, p_function_info);
if (!index_expression) {
return nullptr;
}
- if (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT) {
- _set_error("Only integer expressions are allowed for indexing");
+ if (index_expression->get_array_size() != 0 || (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT)) {
+ _set_error("Only integer expressions are allowed for indexing.");
return nullptr;
}
@@ -3942,6 +5143,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
_set_error("Expected ']'");
return nullptr;
}
+ } else {
+ _set_tkpos(prepos);
}
ArrayNode *arrname = alloc_node<ArrayNode>();
@@ -3952,16 +5155,29 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
arrname->call_expression = call_expression;
arrname->assign_expression = assign_expression;
arrname->is_const = is_const;
+ arrname->array_size = array_size;
+ arrname->is_local = is_local;
expr = arrname;
-
} else {
VariableNode *varname = alloc_node<VariableNode>();
varname->name = identifier;
varname->datatype_cache = data_type;
varname->is_const = is_const;
varname->struct_name = struct_name;
+ varname->is_local = is_local;
expr = varname;
}
+#ifdef DEBUG_ENABLED
+ if (check_warnings) {
+ StringName func_name;
+
+ if (p_block && p_block->parent_function) {
+ func_name = p_block->parent_function->name;
+ }
+
+ _parse_used_identifier(identifier, ident_type, func_name);
+ }
+#endif // DEBUG_ENABLED
}
} else if (tk.type == TK_OP_ADD) {
continue; //this one does nothing
@@ -4012,6 +5228,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
DataType dt = expr->get_datatype();
String st = expr->get_datatype_name();
+ if (!expr->is_indexed() && expr->get_array_size() > 0) {
+ completion_class = TAG_ARRAY;
+ p_block->block_tag = SubClassTag::TAG_ARRAY;
+ Node *call_expression = _parse_and_reduce_expression(p_block, p_function_info);
+ p_block->block_tag = SubClassTag::TAG_GLOBAL;
+ if (!call_expression) {
+ return nullptr;
+ }
+ expr = call_expression;
+ break;
+ }
+
StringName identifier;
if (_get_completable_identifier(p_block, dt == TYPE_STRUCT ? COMPLETION_STRUCT : COMPLETION_INDEX, identifier)) {
if (dt == TYPE_STRUCT) {
@@ -4045,12 +5273,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
String member_name = String(ident.ptr());
if (shader->structs.has(st)) {
StructNode *n = shader->structs[st].shader_struct;
- for (List<MemberNode *>::Element *E = n->members.front(); E; E = E->next()) {
- if (String(E->get()->name) == member_name) {
- member_type = E->get()->datatype;
- array_size = E->get()->array_size;
+ for (const MemberNode *E : n->members) {
+ if (String(E->name) == member_name) {
+ member_type = E->datatype;
+ array_size = E->array_size;
if (member_type == TYPE_STRUCT) {
- member_struct_name = E->get()->struct_name;
+ member_struct_name = E->struct_name;
}
ok = true;
break;
@@ -4288,10 +5516,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
mn->has_swizzling_duplicates = repeated;
if (array_size > 0) {
+ TkPos prev_pos = _get_tkpos();
tk = _get_token();
if (tk.type == TK_OP_ASSIGN) {
- if (last_const) {
- last_const = false;
+ if (last_type == IDENTIFIER_CONSTANT) {
_set_error("Constants cannot be modified.");
return nullptr;
}
@@ -4301,16 +5529,23 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
mn->assign_expression = assign_expression;
} else if (tk.type == TK_PERIOD) {
- _set_error("Nested array length() is not yet implemented");
- return nullptr;
+ completion_class = TAG_ARRAY;
+ p_block->block_tag = SubClassTag::TAG_ARRAY;
+ Node *call_expression = _parse_and_reduce_expression(p_block, p_function_info);
+ p_block->block_tag = SubClassTag::TAG_GLOBAL;
+ if (!call_expression) {
+ return nullptr;
+ }
+ mn->datatype = call_expression->get_datatype();
+ mn->call_expression = call_expression;
} else if (tk.type == TK_BRACKET_OPEN) {
Node *index_expression = _parse_and_reduce_expression(p_block, p_function_info);
if (!index_expression) {
return nullptr;
}
- if (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT) {
- _set_error("Only integer expressions are allowed for indexing");
+ if (index_expression->get_array_size() != 0 || (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT)) {
+ _set_error("Only integer expressions are allowed for indexing.");
return nullptr;
}
@@ -4333,13 +5568,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
mn->index_expression = index_expression;
-
} else {
- _set_error("Expected '[','.' or '='");
- return nullptr;
+ _set_tkpos(prev_pos);
}
}
-
expr = mn;
//todo
@@ -4358,123 +5590,138 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
- if (index->get_datatype() != TYPE_INT && index->get_datatype() != TYPE_UINT) {
- _set_error("Only integer datatypes are allowed for indexing");
+ if (index->get_array_size() != 0 || (index->get_datatype() != TYPE_INT && index->get_datatype() != TYPE_UINT)) {
+ _set_error("Only integer expressions are allowed for indexing.");
return nullptr;
}
DataType member_type = TYPE_VOID;
+ String member_struct_name;
- switch (expr->get_datatype()) {
- case TYPE_BVEC2:
- case TYPE_VEC2:
- case TYPE_IVEC2:
- case TYPE_UVEC2:
- case TYPE_MAT2:
- if (index->type == Node::TYPE_CONSTANT) {
- uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
- if (index_constant >= 2) {
- _set_error("Index out of range (0-1)");
- return nullptr;
- }
+ if (expr->get_array_size() > 0) {
+ if (index->type == Node::TYPE_CONSTANT) {
+ uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
+ if (index_constant >= (uint32_t)expr->get_array_size()) {
+ _set_error(vformat("Index [%s] out of range [%s..%s]", index_constant, 0, expr->get_array_size() - 1));
+ return nullptr;
}
+ }
+ member_type = expr->get_datatype();
+ if (member_type == TYPE_STRUCT) {
+ member_struct_name = expr->get_datatype_name();
+ }
+ } else {
+ switch (expr->get_datatype()) {
+ case TYPE_BVEC2:
+ case TYPE_VEC2:
+ case TYPE_IVEC2:
+ case TYPE_UVEC2:
+ case TYPE_MAT2:
+ if (index->type == Node::TYPE_CONSTANT) {
+ uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
+ if (index_constant >= 2) {
+ _set_error("Index out of range (0-1)");
+ return nullptr;
+ }
+ }
- switch (expr->get_datatype()) {
- case TYPE_BVEC2:
- member_type = TYPE_BOOL;
- break;
- case TYPE_VEC2:
- member_type = TYPE_FLOAT;
- break;
- case TYPE_IVEC2:
- member_type = TYPE_INT;
- break;
- case TYPE_UVEC2:
- member_type = TYPE_UINT;
- break;
- case TYPE_MAT2:
- member_type = TYPE_VEC2;
- break;
- default:
- break;
- }
+ switch (expr->get_datatype()) {
+ case TYPE_BVEC2:
+ member_type = TYPE_BOOL;
+ break;
+ case TYPE_VEC2:
+ member_type = TYPE_FLOAT;
+ break;
+ case TYPE_IVEC2:
+ member_type = TYPE_INT;
+ break;
+ case TYPE_UVEC2:
+ member_type = TYPE_UINT;
+ break;
+ case TYPE_MAT2:
+ member_type = TYPE_VEC2;
+ break;
+ default:
+ break;
+ }
- break;
- case TYPE_BVEC3:
- case TYPE_VEC3:
- case TYPE_IVEC3:
- case TYPE_UVEC3:
- case TYPE_MAT3:
- if (index->type == Node::TYPE_CONSTANT) {
- uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
- if (index_constant >= 3) {
- _set_error("Index out of range (0-2)");
- return nullptr;
+ break;
+ case TYPE_BVEC3:
+ case TYPE_VEC3:
+ case TYPE_IVEC3:
+ case TYPE_UVEC3:
+ case TYPE_MAT3:
+ if (index->type == Node::TYPE_CONSTANT) {
+ uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
+ if (index_constant >= 3) {
+ _set_error("Index out of range (0-2)");
+ return nullptr;
+ }
}
- }
- switch (expr->get_datatype()) {
- case TYPE_BVEC3:
- member_type = TYPE_BOOL;
- break;
- case TYPE_VEC3:
- member_type = TYPE_FLOAT;
- break;
- case TYPE_IVEC3:
- member_type = TYPE_INT;
- break;
- case TYPE_UVEC3:
- member_type = TYPE_UINT;
- break;
- case TYPE_MAT3:
- member_type = TYPE_VEC3;
- break;
- default:
- break;
- }
- break;
- case TYPE_BVEC4:
- case TYPE_VEC4:
- case TYPE_IVEC4:
- case TYPE_UVEC4:
- case TYPE_MAT4:
- if (index->type == Node::TYPE_CONSTANT) {
- uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
- if (index_constant >= 4) {
- _set_error("Index out of range (0-3)");
- return nullptr;
+ switch (expr->get_datatype()) {
+ case TYPE_BVEC3:
+ member_type = TYPE_BOOL;
+ break;
+ case TYPE_VEC3:
+ member_type = TYPE_FLOAT;
+ break;
+ case TYPE_IVEC3:
+ member_type = TYPE_INT;
+ break;
+ case TYPE_UVEC3:
+ member_type = TYPE_UINT;
+ break;
+ case TYPE_MAT3:
+ member_type = TYPE_VEC3;
+ break;
+ default:
+ break;
+ }
+ break;
+ case TYPE_BVEC4:
+ case TYPE_VEC4:
+ case TYPE_IVEC4:
+ case TYPE_UVEC4:
+ case TYPE_MAT4:
+ if (index->type == Node::TYPE_CONSTANT) {
+ uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
+ if (index_constant >= 4) {
+ _set_error("Index out of range (0-3)");
+ return nullptr;
+ }
}
- }
- switch (expr->get_datatype()) {
- case TYPE_BVEC4:
- member_type = TYPE_BOOL;
- break;
- case TYPE_VEC4:
- member_type = TYPE_FLOAT;
- break;
- case TYPE_IVEC4:
- member_type = TYPE_INT;
- break;
- case TYPE_UVEC4:
- member_type = TYPE_UINT;
- break;
- case TYPE_MAT4:
- member_type = TYPE_VEC4;
- break;
- default:
- break;
+ switch (expr->get_datatype()) {
+ case TYPE_BVEC4:
+ member_type = TYPE_BOOL;
+ break;
+ case TYPE_VEC4:
+ member_type = TYPE_FLOAT;
+ break;
+ case TYPE_IVEC4:
+ member_type = TYPE_INT;
+ break;
+ case TYPE_UVEC4:
+ member_type = TYPE_UINT;
+ break;
+ case TYPE_MAT4:
+ member_type = TYPE_VEC4;
+ break;
+ default:
+ break;
+ }
+ break;
+ default: {
+ _set_error("Object of type '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' can't be indexed");
+ return nullptr;
}
- break;
- default: {
- _set_error("Object of type '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' can't be indexed");
- return nullptr;
}
}
-
OperatorNode *op = alloc_node<OperatorNode>();
op->op = OP_INDEX;
op->return_cache = member_type;
+ op->struct_name = member_struct_name;
op->arguments.push_back(expr);
op->arguments.push_back(index);
expr = op;
@@ -4490,7 +5737,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
op->op = tk.type == TK_OP_DECREMENT ? OP_POST_DECREMENT : OP_POST_INCREMENT;
op->arguments.push_back(expr);
- if (!_validate_operator(op, &op->return_cache)) {
+ if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
_set_error("Invalid base type for increment/decrement operator");
return nullptr;
}
@@ -4641,9 +5888,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
bool unary = false;
bool ternary = false;
+ Operator op = expression[i].op;
int priority;
- switch (expression[i].op) {
+ switch (op) {
case OP_EQUAL:
priority = 8;
break;
@@ -4764,6 +6012,14 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
ERR_FAIL_V(nullptr); //unexpected operator
}
+#if DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::FLOAT_COMPARISON_FLAG) && (op == OP_EQUAL || op == OP_NOT_EQUAL) &&
+ (!expression[i - 1].is_op && !expression[i + 1].is_op) &&
+ (expression[i - 1].node->get_datatype() == TYPE_FLOAT && expression[i + 1].node->get_datatype() == TYPE_FLOAT)) {
+ _add_line_warning(ShaderWarning::FLOAT_COMPARISON);
+ }
+#endif // DEBUG_ENABLED
+
if (priority < min_priority) {
// < is used for left to right (default)
// <= is used for right to left
@@ -4801,18 +6057,23 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expression.write[i].is_op = false;
expression.write[i].node = op;
- if (!_validate_operator(op, &op->return_cache)) {
+ if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
String at;
for (int j = 0; j < op->arguments.size(); j++) {
if (j > 0) {
at += " and ";
}
at += get_datatype_name(op->arguments[j]->get_datatype());
+ if (!op->arguments[j]->is_indexed() && op->arguments[j]->get_array_size() > 0) {
+ at += "[";
+ at += itos(op->arguments[j]->get_array_size());
+ at += "]";
+ }
}
_set_error("Invalid arguments to unary operator '" + get_operator_text(op->op) + "' :" + at);
return nullptr;
}
- expression.remove(i + 1);
+ expression.remove_at(i + 1);
}
} else if (is_ternary) {
@@ -4834,20 +6095,25 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expression.write[next_op - 1].is_op = false;
expression.write[next_op - 1].node = op;
- if (!_validate_operator(op, &op->return_cache)) {
+ if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
String at;
for (int i = 0; i < op->arguments.size(); i++) {
if (i > 0) {
at += " and ";
}
at += get_datatype_name(op->arguments[i]->get_datatype());
+ if (!op->arguments[i]->is_indexed() && op->arguments[i]->get_array_size() > 0) {
+ at += "[";
+ at += itos(op->arguments[i]->get_array_size());
+ at += "]";
+ }
}
_set_error("Invalid argument to ternary ?: operator: " + at);
return nullptr;
}
for (int i = 0; i < 4; i++) {
- expression.remove(next_op);
+ expression.remove_at(next_op);
}
} else {
@@ -4887,7 +6153,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
//replace all 3 nodes by this operator and make it an expression
- if (!_validate_operator(op, &op->return_cache)) {
+ if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
String at;
for (int i = 0; i < op->arguments.size(); i++) {
if (i > 0) {
@@ -4898,13 +6164,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else {
at += get_datatype_name(op->arguments[i]->get_datatype());
}
+ if (!op->arguments[i]->is_indexed() && op->arguments[i]->get_array_size() > 0) {
+ at += "[";
+ at += itos(op->arguments[i]->get_array_size());
+ at += "]";
+ }
}
_set_error("Invalid arguments to operator '" + get_operator_text(op->op) + "' :" + at);
return nullptr;
}
- expression.remove(next_op);
- expression.remove(next_op);
+ expression.remove_at(next_op);
+ expression.remove_at(next_op);
}
}
@@ -5108,11 +6379,46 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
Node *vardecl = nullptr;
while (true) {
- if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier after type");
+ bool unknown_size = false;
+ int array_size = 0;
+
+ ArrayDeclarationNode *anode = nullptr;
+ ArrayDeclarationNode::Declaration adecl;
+
+ if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) {
+ _set_error("Expected identifier or '[' after type.");
return ERR_PARSE_ERROR;
}
+ if (tk.type == TK_BRACKET_OPEN) {
+ anode = alloc_node<ArrayDeclarationNode>();
+
+ if (is_struct) {
+ anode->struct_name = struct_name;
+ anode->datatype = TYPE_STRUCT;
+ } else {
+ anode->datatype = type;
+ }
+
+ anode->precision = precision;
+ anode->is_const = is_const;
+ vardecl = (Node *)anode;
+
+ adecl.size = 0U;
+ adecl.single_expression = false;
+
+ Error error = _parse_local_array_size(p_block, p_function_info, anode, &adecl, array_size, unknown_size);
+ if (error != OK) {
+ return error;
+ }
+ tk = _get_token();
+
+ if (tk.type != TK_IDENTIFIER) {
+ _set_error("Expected identifier!");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
StringName name = tk.text;
ShaderLanguage::IdentifierType itype;
if (_find_identifier(p_block, true, p_function_info, name, (ShaderLanguage::DataType *)nullptr, &itype)) {
@@ -5122,290 +6428,283 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
}
+ adecl.name = name;
+
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG)) {
+ if (p_block && p_block->parent_function) {
+ StringName func_name = p_block->parent_function->name;
+
+ if (!used_local_vars.has(func_name)) {
+ used_local_vars.insert(func_name, Map<StringName, Usage>());
+ }
+
+ used_local_vars[func_name].insert(name, Usage(tk_line));
+ }
+ }
+#endif // DEBUG_ENABLED
+
BlockNode::Variable var;
var.type = type;
var.precision = precision;
var.line = tk_line;
- var.array_size = 0;
+ var.array_size = array_size;
var.is_const = is_const;
var.struct_name = struct_name;
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
- bool unknown_size = false;
+ if (var.array_size > 0 || unknown_size) {
+ _set_error("Array size is already defined!");
+ return ERR_PARSE_ERROR;
+ }
if (RenderingServer::get_singleton()->is_low_end() && is_const) {
_set_error("Local const arrays are supported only on high-end platform!");
return ERR_PARSE_ERROR;
}
- ArrayDeclarationNode *node = alloc_node<ArrayDeclarationNode>();
+ anode = alloc_node<ArrayDeclarationNode>();
if (is_struct) {
- node->struct_name = struct_name;
- node->datatype = TYPE_STRUCT;
+ anode->struct_name = struct_name;
+ anode->datatype = TYPE_STRUCT;
} else {
- node->datatype = type;
+ anode->datatype = type;
}
- node->precision = precision;
- node->is_const = is_const;
- vardecl = (Node *)node;
+ anode->precision = precision;
+ anode->is_const = is_const;
+ vardecl = (Node *)anode;
- ArrayDeclarationNode::Declaration decl;
- decl.name = name;
- decl.size = 0U;
+ adecl.size = 0U;
+ adecl.single_expression = false;
- pos = _get_tkpos();
- tk = _get_token();
-
- if (tk.type == TK_BRACKET_CLOSE) {
- unknown_size = true;
- } else {
- if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) {
- _set_tkpos(pos);
- Node *n = _parse_and_reduce_expression(p_block, p_function_info);
- if (n) {
- if (n->type == Node::TYPE_VARIABLE) {
- VariableNode *vn = static_cast<VariableNode *>(n);
- if (vn) {
- ConstantNode::Value v;
- DataType data_type;
-
- _find_identifier(p_block, false, p_function_info, vn->name, &data_type, nullptr, &is_const, nullptr, nullptr, &v);
-
- if (is_const) {
- if (data_type == TYPE_INT) {
- int32_t value = v.sint;
- if (value > 0) {
- node->size_expression = n;
- decl.size = (uint32_t)value;
- }
- } else if (data_type == TYPE_UINT) {
- uint32_t value = v.uint;
- if (value > 0U) {
- node->size_expression = n;
- decl.size = value;
- }
- }
- }
- }
- } else if (n->type == Node::TYPE_OPERATOR) {
- _set_error("Array size expressions are not yet implemented.");
- return ERR_PARSE_ERROR;
- }
- }
- } else if (((int)tk.constant) > 0) {
- decl.size = (uint32_t)tk.constant;
- }
-
- if (decl.size == 0U) {
- _set_error("Expected integer constant > 0 or ']'");
- return ERR_PARSE_ERROR;
- }
- tk = _get_token();
-
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
- }
- var.array_size = decl.size;
+ Error error = _parse_local_array_size(p_block, p_function_info, anode, &adecl, var.array_size, unknown_size);
+ if (error != OK) {
+ return error;
}
+ tk = _get_token();
+ }
+ if (var.array_size > 0 || unknown_size) {
bool full_def = false;
- tk = _get_token();
if (tk.type == TK_OP_ASSIGN) {
if (RenderingServer::get_singleton()->is_low_end()) {
_set_error("Array initialization is supported only on high-end platform!");
return ERR_PARSE_ERROR;
}
+ TkPos prev_pos = _get_tkpos();
tk = _get_token();
- if (tk.type != TK_CURLY_BRACKET_OPEN) {
- if (unknown_size) {
- _set_error("Expected '{'");
- return ERR_PARSE_ERROR;
- }
-
- full_def = true;
+ if (tk.type == TK_IDENTIFIER) { // a function call array initialization
+ _set_tkpos(prev_pos);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
- DataPrecision precision2 = PRECISION_DEFAULT;
- if (is_token_precision(tk.type)) {
- precision2 = get_token_precision(tk.type);
- tk = _get_token();
- if (shader->structs.has(tk.text)) {
- _set_error("Precision modifier cannot be used on structs.");
- return ERR_PARSE_ERROR;
+ if (!n) {
+ _set_error("Expected correct array initializer!");
+ return ERR_PARSE_ERROR;
+ } else {
+ if (unknown_size) {
+ adecl.size = n->get_array_size();
+ var.array_size = n->get_array_size();
}
- if (!is_token_nonvoid_datatype(tk.type)) {
- _set_error("Expected datatype after precision");
+
+ if (!_compare_datatypes(var.type, var.struct_name, var.array_size, n->get_datatype(), n->get_datatype_name(), n->get_array_size())) {
return ERR_PARSE_ERROR;
}
- }
- DataType type2;
- StringName struct_name2 = "";
+ adecl.single_expression = true;
+ adecl.initializer.push_back(n);
+ }
- if (shader->structs.has(tk.text)) {
- type2 = TYPE_STRUCT;
- struct_name2 = tk.text;
- } else {
- if (!is_token_variable_datatype(tk.type)) {
- _set_error("Invalid data type for array");
+ tk = _get_token();
+ } else {
+ if (tk.type != TK_CURLY_BRACKET_OPEN) {
+ if (unknown_size) {
+ _set_error("Expected '{'");
return ERR_PARSE_ERROR;
}
- type2 = get_token_datatype(tk.type);
- }
- int array_size2 = 0;
+ full_def = true;
- tk = _get_token();
- if (tk.type == TK_BRACKET_OPEN) {
- TkPos pos2 = _get_tkpos();
- tk = _get_token();
- if (tk.type == TK_BRACKET_CLOSE) {
- array_size2 = var.array_size;
+ DataPrecision precision2 = PRECISION_DEFAULT;
+ if (is_token_precision(tk.type)) {
+ precision2 = get_token_precision(tk.type);
tk = _get_token();
- } else {
- _set_tkpos(pos2);
-
- Node *n = _parse_and_reduce_expression(p_block, p_function_info);
- if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
- _set_error("Expected single integer constant > 0");
+ if (shader->structs.has(tk.text)) {
+ _set_error("Precision modifier cannot be used on structs.");
return ERR_PARSE_ERROR;
}
+ if (!is_token_nonvoid_datatype(tk.type)) {
+ _set_error("Expected datatype after precision");
+ return ERR_PARSE_ERROR;
+ }
+ }
- ConstantNode *cnode = (ConstantNode *)n;
- if (cnode->values.size() == 1) {
- array_size2 = cnode->values[0].sint;
- if (array_size2 <= 0) {
- _set_error("Expected single integer constant > 0");
- return ERR_PARSE_ERROR;
- }
- } else {
- _set_error("Expected single integer constant > 0");
+ DataType type2;
+ StringName struct_name2 = "";
+
+ if (shader->structs.has(tk.text)) {
+ type2 = TYPE_STRUCT;
+ struct_name2 = tk.text;
+ } else {
+ if (!is_token_variable_datatype(tk.type)) {
+ _set_error("Invalid data type for array");
return ERR_PARSE_ERROR;
}
+ type2 = get_token_datatype(tk.type);
+ }
+ int array_size2 = 0;
+
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_OPEN) {
+ TkPos pos2 = _get_tkpos();
tk = _get_token();
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
+ if (tk.type == TK_BRACKET_CLOSE) {
+ array_size2 = var.array_size;
+ tk = _get_token();
} else {
+ _set_tkpos(pos2);
+
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
+ if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
+ _set_error("Expected single integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+
+ ConstantNode *cnode = (ConstantNode *)n;
+ if (cnode->values.size() == 1) {
+ array_size2 = cnode->values[0].sint;
+ if (array_size2 <= 0) {
+ _set_error("Expected single integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ _set_error("Expected single integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+
tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ } else {
+ tk = _get_token();
+ }
}
- }
- } else {
- _set_error("Expected '['");
- return ERR_PARSE_ERROR;
- }
-
- if (precision != precision2 || type != type2 || struct_name != struct_name2 || var.array_size != array_size2) {
- String error_str = "Cannot convert from '";
- if (precision2 != PRECISION_DEFAULT) {
- error_str += get_precision_name(precision2);
- error_str += " ";
- }
- if (type2 == TYPE_STRUCT) {
- error_str += struct_name2;
} else {
- error_str += get_datatype_name(type2);
- }
- error_str += "[";
- error_str += itos(array_size2);
- error_str += "]'";
- error_str += " to '";
- if (precision != PRECISION_DEFAULT) {
- error_str += get_precision_name(precision);
- error_str += " ";
+ _set_error("Expected '['");
+ return ERR_PARSE_ERROR;
}
- if (type == TYPE_STRUCT) {
- error_str += struct_name;
- } else {
- error_str += get_datatype_name(type);
+
+ if (precision != precision2 || type != type2 || struct_name != struct_name2 || var.array_size != array_size2) {
+ String error_str = "Cannot convert from '";
+ if (precision2 != PRECISION_DEFAULT) {
+ error_str += get_precision_name(precision2);
+ error_str += " ";
+ }
+ if (type2 == TYPE_STRUCT) {
+ error_str += struct_name2;
+ } else {
+ error_str += get_datatype_name(type2);
+ }
+ error_str += "[";
+ error_str += itos(array_size2);
+ error_str += "]'";
+ error_str += " to '";
+ if (precision != PRECISION_DEFAULT) {
+ error_str += get_precision_name(precision);
+ error_str += " ";
+ }
+ if (type == TYPE_STRUCT) {
+ error_str += struct_name;
+ } else {
+ error_str += get_datatype_name(type);
+ }
+ error_str += "[";
+ error_str += itos(var.array_size);
+ error_str += "]'";
+ _set_error(error_str);
+ return ERR_PARSE_ERROR;
}
- error_str += "[";
- error_str += itos(var.array_size);
- error_str += "]'";
- _set_error(error_str);
- return ERR_PARSE_ERROR;
}
- }
- bool curly = tk.type == TK_CURLY_BRACKET_OPEN;
+ bool curly = tk.type == TK_CURLY_BRACKET_OPEN;
- if (unknown_size) {
- if (!curly) {
- _set_error("Expected '{'");
- return ERR_PARSE_ERROR;
- }
- } else {
- if (full_def) {
- if (curly) {
- _set_error("Expected '('");
+ if (unknown_size) {
+ if (!curly) {
+ _set_error("Expected '{'");
return ERR_PARSE_ERROR;
}
+ } else {
+ if (full_def) {
+ if (curly) {
+ _set_error("Expected '('");
+ return ERR_PARSE_ERROR;
+ }
+ }
}
- }
- if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization
- while (true) {
- Node *n = _parse_and_reduce_expression(p_block, p_function_info);
- if (!n) {
- return ERR_PARSE_ERROR;
- }
+ if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization
+ while (true) {
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
+ if (!n) {
+ return ERR_PARSE_ERROR;
+ }
- if (node->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) {
- _set_error("Expected constant expression");
- return ERR_PARSE_ERROR;
- }
+ if (anode->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) {
+ _set_error("Expected constant expression");
+ return ERR_PARSE_ERROR;
+ }
- if (var.type != n->get_datatype() || struct_name != n->get_datatype_name()) {
- _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (var.type == TYPE_STRUCT ? struct_name : get_datatype_name(var.type)) + "'");
- return ERR_PARSE_ERROR;
- }
+ if (!_compare_datatypes(var.type, struct_name, 0, n->get_datatype(), n->get_datatype_name(), 0)) {
+ return ERR_PARSE_ERROR;
+ }
- tk = _get_token();
- if (tk.type == TK_COMMA) {
- decl.initializer.push_back(n);
- continue;
- } else if (!curly && tk.type == TK_PARENTHESIS_CLOSE) {
- decl.initializer.push_back(n);
- break;
- } else if (curly && tk.type == TK_CURLY_BRACKET_CLOSE) {
- decl.initializer.push_back(n);
- break;
- } else {
- if (curly) {
- _set_error("Expected '}' or ','");
+ tk = _get_token();
+ if (tk.type == TK_COMMA) {
+ adecl.initializer.push_back(n);
+ continue;
+ } else if (!curly && tk.type == TK_PARENTHESIS_CLOSE) {
+ adecl.initializer.push_back(n);
+ break;
+ } else if (curly && tk.type == TK_CURLY_BRACKET_CLOSE) {
+ adecl.initializer.push_back(n);
+ break;
} else {
- _set_error("Expected ')' or ','");
+ if (curly) {
+ _set_error("Expected '}' or ','");
+ } else {
+ _set_error("Expected ')' or ','");
+ }
+ return ERR_PARSE_ERROR;
}
+ }
+ if (unknown_size) {
+ adecl.size = adecl.initializer.size();
+ var.array_size = adecl.initializer.size();
+ } else if (adecl.initializer.size() != var.array_size) {
+ _set_error("Array size mismatch");
return ERR_PARSE_ERROR;
}
+ tk = _get_token();
}
- if (unknown_size) {
- decl.size = decl.initializer.size();
- var.array_size = decl.initializer.size();
- } else if (decl.initializer.size() != var.array_size) {
- _set_error("Array size mismatch");
- return ERR_PARSE_ERROR;
- }
- tk = _get_token();
}
} else {
if (unknown_size) {
_set_error("Expected array initialization");
return ERR_PARSE_ERROR;
}
- if (node->is_const) {
+ if (anode->is_const) {
_set_error("Expected initialization of constant");
return ERR_PARSE_ERROR;
}
}
- node->declarations.push_back(decl);
+ anode->declarations.push_back(adecl);
} else if (tk.type == TK_OP_ASSIGN) {
VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>();
if (is_struct) {
@@ -5445,8 +6744,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
}
- if (var.type == TYPE_STRUCT ? (var.struct_name != n->get_datatype_name()) : (var.type != n->get_datatype())) {
- _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (var.type == TYPE_STRUCT ? String(var.struct_name) : get_datatype_name(var.type)) + "'");
+ if (!_compare_datatypes(var.type, var.struct_name, var.array_size, n->get_datatype(), n->get_datatype_name(), n->get_array_size())) {
return ERR_PARSE_ERROR;
}
tk = _get_token();
@@ -5476,7 +6774,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
p_block->statements.push_back(vardecl);
p_block->variables[name] = var;
-
if (tk.type == TK_COMMA) {
if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR) {
_set_error("Multiple declarations in 'for' loop are not implemented yet.");
@@ -5893,11 +7190,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
//check return type
BlockNode *b = p_block;
- if (b && b->parent_function && p_function_info.main_function) {
- _set_error(vformat("Using 'return' in '%s' processor function results in undefined behavior!", b->parent_function->name));
- return ERR_PARSE_ERROR;
- }
-
while (b && !b->parent_function) {
b = b->parent_block;
}
@@ -5907,7 +7199,17 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_BUG;
}
+ if (b && b->parent_function && p_function_info.main_function) {
+ _set_error(vformat("Using 'return' in '%s' processor function results in undefined behavior!", b->parent_function->name));
+ return ERR_PARSE_ERROR;
+ }
+
String return_struct_name = String(b->parent_function->return_struct_name);
+ String array_size_string;
+
+ if (b->parent_function->return_array_size > 0) {
+ array_size_string = "[" + itos(b->parent_function->return_array_size) + "]";
+ }
ControlFlowNode *flow = alloc_node<ControlFlowNode>();
flow->flow_op = FLOW_OP_RETURN;
@@ -5917,18 +7219,19 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (tk.type == TK_SEMICOLON) {
//all is good
if (b->parent_function->return_type != TYPE_VOID) {
- _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + "'");
+ _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string + "'");
return ERR_PARSE_ERROR;
}
} else {
_set_tkpos(pos); //rollback, wants expression
+
Node *expr = _parse_and_reduce_expression(p_block, p_function_info);
if (!expr) {
return ERR_PARSE_ERROR;
}
- if (b->parent_function->return_type != expr->get_datatype() || return_struct_name != expr->get_datatype_name()) {
- _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + "'");
+ if (b->parent_function->return_type != expr->get_datatype() || b->parent_function->return_array_size != expr->get_array_size() || return_struct_name != expr->get_datatype_name()) {
+ _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string + "'");
return ERR_PARSE_ERROR;
}
@@ -6103,6 +7406,7 @@ Error ShaderLanguage::_validate_datatype(DataType p_type) {
Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types) {
Token tk = _get_token();
+ TkPos prev_pos;
if (tk.type != TK_SHADER_TYPE) {
_set_error("Expected 'shader_type' at the beginning of shader. Valid types are: " + _get_shader_type_list(p_shader_types));
@@ -6124,16 +7428,19 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
_set_error("Invalid shader type. Valid types are: " + _get_shader_type_list(p_shader_types));
return ERR_PARSE_ERROR;
}
-
+ prev_pos = _get_tkpos();
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
+ _set_tkpos(prev_pos);
_set_error("Expected ';' after 'shader_type <type>'.");
+ return ERR_PARSE_ERROR;
}
tk = _get_token();
int texture_uniforms = 0;
+ int texture_binding = 0;
int uniforms = 0;
int instance_index = 0;
ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
@@ -6244,8 +7551,23 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
_set_error("void datatype not allowed here");
return ERR_PARSE_ERROR;
}
-
tk = _get_token();
+
+ if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) {
+ _set_error("Expected identifier or '['.");
+ return ERR_PARSE_ERROR;
+ }
+
+ int array_size = 0;
+
+ if (tk.type == TK_BRACKET_OPEN) {
+ Error error = _parse_global_array_size(array_size);
+ if (error != OK) {
+ return error;
+ }
+ tk = _get_token();
+ }
+
if (tk.type != TK_IDENTIFIER) {
_set_error("Expected identifier!");
return ERR_PARSE_ERROR;
@@ -6256,41 +7578,29 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
member->datatype = type;
member->struct_name = struct_name;
member->name = tk.text;
+ member->array_size = array_size;
if (member_names.has(member->name)) {
_set_error("Redefinition of '" + String(member->name) + "'");
return ERR_PARSE_ERROR;
}
member_names.insert(member->name);
-
tk = _get_token();
- if (tk.type == TK_BRACKET_OPEN) {
- tk = _get_token();
- if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
- member->array_size = (int)tk.constant;
- tk = _get_token();
- if (tk.type == TK_BRACKET_CLOSE) {
- tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';'");
- return ERR_PARSE_ERROR;
- }
- } else {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
- }
- } else {
- _set_error("Expected single integer constant > 0");
- return ERR_PARSE_ERROR;
+ if (tk.type == TK_BRACKET_OPEN) {
+ Error error = _parse_global_array_size(member->array_size);
+ if (error != OK) {
+ return error;
}
+ tk = _get_token();
}
- st_node->members.push_back(member);
if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ']' or ';'");
+ _set_error("Expected ';'");
return ERR_PARSE_ERROR;
}
+
+ st_node->members.push_back(member);
member_count++;
}
}
@@ -6306,7 +7616,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
shader->structs[st.name] = st;
shader->vstructs.push_back(st); // struct's order is important!
-
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_STRUCT_FLAG)) {
+ used_structs.insert(st.name, Usage(tk_line));
+ }
+#endif // DEBUG_ENABLED
} break;
case TK_GLOBAL: {
tk = _get_token();
@@ -6333,28 +7647,49 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
bool uniform = tk.type == TK_UNIFORM;
if (!uniform) {
- if (shader_type_identifier == "particles" || shader_type_identifier == "sky") {
+ if (shader_type_identifier == "particles" || shader_type_identifier == "sky" || shader_type_identifier == "fog") {
_set_error(vformat("Varyings cannot be used in '%s' shaders!", shader_type_identifier));
return ERR_PARSE_ERROR;
}
}
+ bool precision_defined = false;
DataPrecision precision = PRECISION_DEFAULT;
DataInterpolation interpolation = INTERPOLATION_SMOOTH;
DataType type;
StringName name;
+ int array_size = 0;
tk = _get_token();
if (is_token_interpolation(tk.type)) {
+ if (uniform) {
+ _set_error("Interpolation qualifiers are not supported for uniforms!");
+ return ERR_PARSE_ERROR;
+ }
interpolation = get_token_interpolation(tk.type);
tk = _get_token();
}
if (is_token_precision(tk.type)) {
precision = get_token_precision(tk.type);
+ precision_defined = true;
tk = _get_token();
}
+ if (shader->structs.has(tk.text)) {
+ if (uniform) {
+ if (precision_defined) {
+ _set_error("Precision modifier cannot be used on structs.");
+ return ERR_PARSE_ERROR;
+ }
+ _set_error("struct datatype is not yet supported for uniforms!");
+ return ERR_PARSE_ERROR;
+ } else {
+ _set_error("struct datatype not allowed here");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
if (!is_token_datatype(tk.type)) {
_set_error("Expected datatype. ");
return ERR_PARSE_ERROR;
@@ -6373,12 +7708,26 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
tk = _get_token();
+
+ if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) {
+ _set_error("Expected identifier or '['.");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (tk.type == TK_BRACKET_OPEN) {
+ Error error = _parse_global_array_size(array_size);
+ if (error != OK) {
+ return error;
+ }
+ tk = _get_token();
+ }
+
if (tk.type != TK_IDENTIFIER) {
_set_error("Expected identifier!");
return ERR_PARSE_ERROR;
}
- TkPos name_pos = _get_tkpos();
+ prev_pos = _get_tkpos();
name = tk.text;
if (_find_identifier(nullptr, false, FunctionInfo(), name)) {
@@ -6407,12 +7756,32 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
ShaderNode::Uniform uniform2;
+ uniform2.type = type;
+ uniform2.scope = uniform_scope;
+ uniform2.precision = precision;
+ uniform2.array_size = array_size;
+
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_OPEN) {
+ Error error = _parse_global_array_size(uniform2.array_size);
+ if (error != OK) {
+ return error;
+ }
+ tk = _get_token();
+ }
+
if (is_sampler_type(type)) {
if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) {
_set_error("Uniforms with 'instance' qualifiers can't be of sampler type.");
return ERR_PARSE_ERROR;
}
uniform2.texture_order = texture_uniforms++;
+ uniform2.texture_binding = texture_binding;
+ if (uniform2.array_size > 0) {
+ texture_binding += uniform2.array_size;
+ } else {
+ ++texture_binding;
+ }
uniform2.order = -1;
if (_validate_datatype(type) != OK) {
return ERR_PARSE_ERROR;
@@ -6422,19 +7791,22 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
_set_error("Uniforms with 'instance' qualifiers can't be of matrix type.");
return ERR_PARSE_ERROR;
}
-
uniform2.texture_order = -1;
if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) {
uniform2.order = uniforms++;
}
}
- uniform2.type = type;
- uniform2.scope = uniform_scope;
- uniform2.precision = precision;
- //todo parse default value
-
- tk = _get_token();
+ if (uniform2.array_size > 0) {
+ if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL) {
+ _set_error("'SCOPE_GLOBAL' qualifier is not yet supported for uniform array!");
+ return ERR_PARSE_ERROR;
+ }
+ if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) {
+ _set_error("'SCOPE_INSTANCE' qualifier is not yet supported for uniform array!");
+ return ERR_PARSE_ERROR;
+ }
+ }
int custom_instance_index = -1;
@@ -6442,6 +7814,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
//hint
do {
tk = _get_token();
+
+ if (uniform2.array_size > 0) {
+ if (tk.type != TK_HINT_COLOR) {
+ _set_error("This hint is not yet supported for uniform arrays!");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
if (tk.type == TK_HINT_WHITE_TEXTURE) {
uniform2.hint = ShaderNode::Uniform::HINT_WHITE;
} else if (tk.type == TK_HINT_BLACK_TEXTURE) {
@@ -6632,6 +8012,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
//reset scope for next uniform
if (tk.type == TK_OP_ASSIGN) {
+ if (uniform2.array_size > 0) {
+ _set_error("Setting default value to a uniform array is not yet supported!");
+ return ERR_PARSE_ERROR;
+ }
+
Node *expr = _parse_and_reduce_expression(nullptr, FunctionInfo());
if (!expr) {
return ERR_PARSE_ERROR;
@@ -6653,6 +8038,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
shader->uniforms[name] = uniform2;
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_UNIFORM_FLAG)) {
+ used_uniforms.insert(name, Usage(tk_line));
+ }
+#endif // DEBUG_ENABLED
+
//reset scope for next uniform
uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
@@ -6665,15 +8056,24 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
varying.type = type;
varying.precision = precision;
varying.interpolation = interpolation;
- varying.tkpos = name_pos;
+ varying.tkpos = prev_pos;
+ varying.array_size = array_size;
tk = _get_token();
if (tk.type != TK_SEMICOLON && tk.type != TK_BRACKET_OPEN) {
- _set_error("Expected ';' or '['");
+ if (array_size == 0) {
+ _set_error("Expected ';' or '['");
+ } else {
+ _set_error("Expected ';'");
+ }
return ERR_PARSE_ERROR;
}
if (tk.type == TK_BRACKET_OPEN) {
+ if (array_size > 0) {
+ _set_error("Array size is already defined!");
+ return ERR_PARSE_ERROR;
+ }
tk = _get_token();
if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
varying.array_size = (int)tk.constant;
@@ -6690,12 +8090,17 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
} else {
- _set_error("Expected single integer constant > 0");
+ _set_error("Expected integer constant > 0");
return ERR_PARSE_ERROR;
}
}
shader->varyings[name] = varying;
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_VARYING_FLAG)) {
+ used_varyings.insert(name, Usage(tk_line));
+ }
+#endif // DEBUG_ENABLED
}
} break;
@@ -6708,6 +8113,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
DataPrecision precision = PRECISION_DEFAULT;
DataType type;
StringName name;
+ int return_array_size = 0;
if (tk.type == TK_CONST) {
is_constant = true;
@@ -6743,12 +8149,35 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
} else {
type = get_token_datatype(tk.type);
}
- TkPos prev_pos = _get_tkpos();
+ prev_pos = _get_tkpos();
tk = _get_token();
+
if (tk.type == TK_BRACKET_OPEN) {
- _set_error("Cannot use arrays as return types");
- return ERR_PARSE_ERROR;
+ bool error = false;
+ tk = _get_token();
+
+ if (tk.type == TK_INT_CONSTANT) {
+ return_array_size = (int)tk.constant;
+ if (return_array_size > 0) {
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ error = true;
+ }
+ } else {
+ error = true;
+ }
+ if (error) {
+ _set_error("Expected integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+
+ prev_pos = _get_tkpos();
}
+
_set_tkpos(prev_pos);
_get_completable_identifier(nullptr, COMPLETION_MAIN_FUNCTION, name);
@@ -6863,13 +8292,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
- TkPos pos2 = _get_tkpos();
+ prev_pos = _get_tkpos();
tk = _get_token();
if (tk.type == TK_BRACKET_CLOSE) {
array_size2 = constant.array_size;
tk = _get_token();
} else {
- _set_tkpos(pos2);
+ _set_tkpos(prev_pos);
Node *n = _parse_and_reduce_expression(nullptr, FunctionInfo());
if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
@@ -6962,8 +8391,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
- if (constant.type != n->get_datatype() || n->get_datatype_name() != struct_name) {
- _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (is_struct ? String(struct_name) : get_datatype_name(constant.type)) + "'");
+ if (!_compare_datatypes(constant.type, struct_name, 0, n->get_datatype(), n->get_datatype_name(), 0)) {
return ERR_PARSE_ERROR;
}
@@ -7024,8 +8452,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
constant.initializer = static_cast<ConstantNode *>(expr);
- if (type != expr->get_datatype() || expr->get_datatype_name() != struct_name) {
- _set_error("Invalid assignment of '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' to '" + (is_struct ? String(struct_name) : get_datatype_name(type)) + "'");
+ if (!_compare_datatypes(type, struct_name, 0, expr->get_datatype(), expr->get_datatype_name(), 0)) {
return ERR_PARSE_ERROR;
}
}
@@ -7042,6 +8469,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
shader->constants[name] = constant;
shader->vconstants.push_back(constant);
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_CONSTANT_FLAG)) {
+ used_constants.insert(name, Usage(tk_line));
+ }
+#endif // DEBUG_ENABLED
if (tk.type == TK_COMMA) {
tk = _get_token();
@@ -7080,8 +8512,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
if (p_functions.has("global")) { // Adds global variables: 'TIME'
- for (Map<StringName, BuiltInInfo>::Element *E = p_functions["global"].built_ins.front(); E; E = E->next()) {
- builtins.built_ins.insert(E->key(), E->value());
+ for (const KeyValue<StringName, BuiltInInfo> &E : p_functions["global"].built_ins) {
+ builtins.built_ins.insert(E.key, E.value);
}
}
@@ -7100,9 +8532,16 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
func_node->return_type = type;
func_node->return_struct_name = struct_name;
func_node->return_precision = precision;
+ func_node->return_array_size = return_array_size;
if (p_functions.has(name)) {
func_node->can_discard = p_functions[name].can_discard;
+ } else {
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_FUNCTION_FLAG)) {
+ used_functions.insert(name, Usage(tk_line));
+ }
+#endif // DEBUG_ENABLED
}
func_node->body = alloc_node<BlockNode>();
@@ -7147,6 +8586,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
StringName param_struct_name;
DataPrecision pprecision = PRECISION_DEFAULT;
bool use_precision = false;
+ int array_size = 0;
if (is_token_precision(tk.type)) {
pprecision = get_token_precision(tk.type);
@@ -7193,8 +8633,29 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
- _set_error("Arrays as parameters are not implemented yet");
- return ERR_PARSE_ERROR;
+ bool error = false;
+ tk = _get_token();
+
+ if (tk.type == TK_INT_CONSTANT) {
+ array_size = (int)tk.constant;
+
+ if (array_size > 0) {
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ error = true;
+ }
+ } else {
+ error = true;
+ }
+ if (error) {
+ _set_error("Expected integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+ tk = _get_token();
}
if (tk.type != TK_IDENTIFIER) {
_set_error("Expected identifier for argument name");
@@ -7228,14 +8689,41 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
arg.tex_argument_repeat = REPEAT_DEFAULT;
arg.is_const = is_const;
- func_node->arguments.push_back(arg);
-
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
- _set_error("Arrays as parameters are not implemented yet");
- return ERR_PARSE_ERROR;
+ if (array_size > 0) {
+ _set_error("Array size is already defined!");
+ return ERR_PARSE_ERROR;
+ }
+ bool error = false;
+ tk = _get_token();
+
+ if (tk.type == TK_INT_CONSTANT) {
+ array_size = (int)tk.constant;
+
+ if (array_size > 0) {
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ error = true;
+ }
+ } else {
+ error = true;
+ }
+
+ if (error) {
+ _set_error("Expected integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+ tk = _get_token();
}
+ arg.array_size = array_size;
+ func_node->arguments.push_back(arg);
+
if (tk.type == TK_COMMA) {
tk = _get_token();
//do none and go on
@@ -7285,20 +8773,20 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
}
- for (Map<StringName, ShaderNode::Varying>::Element *E = shader->varyings.front(); E; E = E->next()) {
- if (E->get().stage == ShaderNode::Varying::STAGE_VERTEX || E->get().stage == ShaderNode::Varying::STAGE_FRAGMENT) {
- _set_tkpos(E->get().tkpos);
- _set_error(RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'"));
- return ERR_PARSE_ERROR;
- }
+ int error_line;
+ String error_message;
+ if (!_check_varying_usages(&error_line, &error_message)) {
+ _set_tkpos({ 0, error_line });
+ _set_error(error_message);
+ return ERR_PARSE_ERROR;
}
return OK;
}
bool ShaderLanguage::has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name) {
- for (Map<StringName, ShaderLanguage::FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) {
- if (E->get().built_ins.has(p_name)) {
+ for (const KeyValue<StringName, ShaderLanguage::FunctionInfo> &E : p_functions) {
+ if (E.value.built_ins.has(p_name)) {
return true;
}
}
@@ -7436,6 +8924,42 @@ String ShaderLanguage::get_shader_type(const String &p_code) {
return String();
}
+#ifdef DEBUG_ENABLED
+void ShaderLanguage::_check_warning_accums() {
+ for (const KeyValue<ShaderWarning::Code, Map<StringName, Map<StringName, Usage>> *> &E : warnings_check_map2) {
+ for (Map<StringName, Map<StringName, Usage>>::Element *T = (*E.value).front(); T; T = T->next()) {
+ for (const KeyValue<StringName, Usage> &U : T->get()) {
+ if (!U.value.used) {
+ _add_warning(E.key, U.value.decl_line, U.key);
+ }
+ }
+ }
+ }
+ for (const KeyValue<ShaderWarning::Code, Map<StringName, Usage> *> &E : warnings_check_map) {
+ for (const Map<StringName, Usage>::Element *U = (*E.value).front(); U; U = U->next()) {
+ if (!U->get().used) {
+ _add_warning(E.key, U->get().decl_line, U->key());
+ }
+ }
+ }
+}
+List<ShaderWarning>::Element *ShaderLanguage::get_warnings_ptr() {
+ return warnings.front();
+}
+void ShaderLanguage::enable_warning_checking(bool p_enabled) {
+ check_warnings = p_enabled;
+}
+bool ShaderLanguage::is_warning_checking_enabled() const {
+ return check_warnings;
+}
+void ShaderLanguage::set_warning_flags(uint32_t p_flags) {
+ warning_flags = p_flags;
+}
+uint32_t ShaderLanguage::get_warning_flags() const {
+ return warning_flags;
+}
+#endif // DEBUG_ENABLED
+
Error ShaderLanguage::compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func) {
clear();
@@ -7448,6 +8972,12 @@ Error ShaderLanguage::compile(const String &p_code, const Map<StringName, Functi
shader = alloc_node<ShaderNode>();
Error err = _parse_shader(p_functions, p_render_modes, p_shader_types);
+#ifdef DEBUG_ENABLED
+ if (check_warnings) {
+ _check_warning_accums();
+ }
+#endif // DEBUG_ENABLED
+
if (err != OK) {
return err;
}
@@ -7491,8 +9021,8 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
return OK;
} break;
case COMPLETION_MAIN_FUNCTION: {
- for (const Map<StringName, FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) {
- ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_FUNCTION);
+ for (const KeyValue<StringName, FunctionInfo> &E : p_functions) {
+ ScriptCodeCompletionOption option(E.key, ScriptCodeCompletionOption::KIND_FUNCTION);
r_options->push_back(option);
}
@@ -7508,9 +9038,9 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
if (completion_class == TAG_GLOBAL) {
while (block) {
if (comp_ident) {
- for (const Map<StringName, BlockNode::Variable>::Element *E = block->variables.front(); E; E = E->next()) {
- if (E->get().line < completion_line) {
- matches.insert(E->key(), ScriptCodeCompletionOption::KIND_VARIABLE);
+ for (const KeyValue<StringName, BlockNode::Variable> &E : block->variables) {
+ if (E.value.line < completion_line) {
+ matches.insert(E.key, ScriptCodeCompletionOption::KIND_VARIABLE);
}
}
}
@@ -7528,30 +9058,30 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
if (comp_ident) {
if (p_functions.has("global")) {
- for (Map<StringName, BuiltInInfo>::Element *E = p_functions["global"].built_ins.front(); E; E = E->next()) {
+ for (const KeyValue<StringName, BuiltInInfo> &E : p_functions["global"].built_ins) {
ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_MEMBER;
- if (E->get().constant) {
+ if (E.value.constant) {
kind = ScriptCodeCompletionOption::KIND_CONSTANT;
}
- matches.insert(E->key(), kind);
+ matches.insert(E.key, kind);
}
}
if (skip_function != StringName() && p_functions.has(skip_function)) {
- for (Map<StringName, BuiltInInfo>::Element *E = p_functions[skip_function].built_ins.front(); E; E = E->next()) {
+ for (const KeyValue<StringName, BuiltInInfo> &E : p_functions[skip_function].built_ins) {
ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_MEMBER;
- if (E->get().constant) {
+ if (E.value.constant) {
kind = ScriptCodeCompletionOption::KIND_CONSTANT;
}
- matches.insert(E->key(), kind);
+ matches.insert(E.key, kind);
}
}
- for (const Map<StringName, ShaderNode::Varying>::Element *E = shader->varyings.front(); E; E = E->next()) {
- matches.insert(E->key(), ScriptCodeCompletionOption::KIND_VARIABLE);
+ for (const KeyValue<StringName, ShaderNode::Varying> &E : shader->varyings) {
+ matches.insert(E.key, ScriptCodeCompletionOption::KIND_VARIABLE);
}
- for (const Map<StringName, ShaderNode::Uniform>::Element *E = shader->uniforms.front(); E; E = E->next()) {
- matches.insert(E->key(), ScriptCodeCompletionOption::KIND_MEMBER);
+ for (const KeyValue<StringName, ShaderNode::Uniform> &E : shader->uniforms) {
+ matches.insert(E.key, ScriptCodeCompletionOption::KIND_MEMBER);
}
}
@@ -7566,8 +9096,8 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
bool low_end = RenderingServer::get_singleton()->is_low_end();
if (stages && stages->has(skip_function)) {
- for (const Map<StringName, StageFunctionInfo>::Element *E = (*stages)[skip_function].stage_functions.front(); E; E = E->next()) {
- matches.insert(String(E->key()), ScriptCodeCompletionOption::KIND_FUNCTION);
+ for (const KeyValue<StringName, StageFunctionInfo> &E : (*stages)[skip_function].stage_functions) {
+ matches.insert(String(E.key), ScriptCodeCompletionOption::KIND_FUNCTION);
}
}
@@ -7596,9 +9126,9 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
}
}
- for (Map<String, ScriptCodeCompletionOption::Kind>::Element *E = matches.front(); E; E = E->next()) {
- ScriptCodeCompletionOption option(E->key(), E->value());
- if (E->value() == ScriptCodeCompletionOption::KIND_FUNCTION) {
+ for (const KeyValue<String, ScriptCodeCompletionOption::Kind> &E : matches) {
+ ScriptCodeCompletionOption option(E.key, E.value);
+ if (E.value == ScriptCodeCompletionOption::KIND_FUNCTION) {
option.insert_text += "(";
}
r_options->push_back(option);
@@ -7625,6 +9155,13 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
String calltip;
calltip += get_datatype_name(shader->functions[i].function->return_type);
+
+ if (shader->functions[i].function->return_array_size > 0) {
+ calltip += "[";
+ calltip += itos(shader->functions[i].function->return_array_size);
+ calltip += "]";
+ }
+
calltip += " ";
calltip += shader->functions[i].name;
calltip += "(";
@@ -7656,6 +9193,12 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
calltip += " ";
calltip += shader->functions[i].function->arguments[j].name;
+ if (shader->functions[i].function->arguments[j].array_size > 0) {
+ calltip += "[";
+ calltip += itos(shader->functions[i].function->arguments[j].array_size);
+ calltip += "]";
+ }
+
if (j == completion_argument) {
calltip += char32_t(0xFFFF);
}
@@ -7677,14 +9220,14 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
bool low_end = RenderingServer::get_singleton()->is_low_end();
if (stages && stages->has(block_function)) {
- for (const Map<StringName, StageFunctionInfo>::Element *E = (*stages)[block_function].stage_functions.front(); E; E = E->next()) {
- if (completion_function == E->key()) {
- calltip += get_datatype_name(E->get().return_type);
+ for (const KeyValue<StringName, StageFunctionInfo> &E : (*stages)[block_function].stage_functions) {
+ if (completion_function == E.key) {
+ calltip += get_datatype_name(E.value.return_type);
calltip += " ";
- calltip += E->key();
+ calltip += E.key;
calltip += "(";
- for (int i = 0; i < E->get().arguments.size(); i++) {
+ for (int i = 0; i < E.value.arguments.size(); i++) {
if (i > 0) {
calltip += ", ";
} else {
@@ -7695,16 +9238,16 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
calltip += char32_t(0xFFFF);
}
- calltip += get_datatype_name(E->get().arguments[i].type);
+ calltip += get_datatype_name(E.value.arguments[i].type);
calltip += " ";
- calltip += E->get().arguments[i].name;
+ calltip += E.value.arguments[i].name;
if (i == completion_argument) {
calltip += char32_t(0xFFFF);
}
}
- if (E->get().arguments.size()) {
+ if (E.value.arguments.size()) {
calltip += " ";
}
calltip += ")";
@@ -7722,10 +9265,16 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
}
int idx2 = 0;
- int out_arg = -1;
+ Set<int> out_args;
while (builtin_func_out_args[idx2].name != nullptr) {
if (builtin_func_out_args[idx2].name == builtin_func_defs[idx].name) {
- out_arg = builtin_func_out_args[idx2].argument;
+ for (int i = 0; i < BuiltinFuncOutArgs::MAX_ARGS; i++) {
+ int arg = builtin_func_out_args[idx2].arguments[i];
+ if (arg == -1) {
+ break;
+ }
+ out_args.insert(arg);
+ }
break;
}
idx2++;
@@ -7762,12 +9311,18 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
calltip += char32_t(0xFFFF);
}
- if (out_arg >= 0 && i == out_arg) {
+ if (out_args.has(i)) {
calltip += "out ";
}
calltip += get_datatype_name(builtin_func_defs[idx].args[i]);
+ String arg_name = (String)builtin_func_defs[idx].args_names[i];
+ if (!arg_name.is_empty()) {
+ calltip += " ";
+ calltip += arg_name;
+ }
+
if (i == completion_argument) {
calltip += char32_t(0xFFFF);
}
@@ -7817,15 +9372,6 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
limit = 4;
} break;
- case TYPE_MAT2:
- limit = 2;
- break;
- case TYPE_MAT3:
- limit = 3;
- break;
- case TYPE_MAT4:
- limit = 4;
- break;
default: {
}
}
@@ -7857,6 +9403,16 @@ ShaderLanguage::ShaderNode *ShaderLanguage::get_shader() {
ShaderLanguage::ShaderLanguage() {
nodes = nullptr;
completion_class = TAG_GLOBAL;
+
+#if DEBUG_ENABLED
+ warnings_check_map.insert(ShaderWarning::UNUSED_CONSTANT, &used_constants);
+ warnings_check_map.insert(ShaderWarning::UNUSED_FUNCTION, &used_functions);
+ warnings_check_map.insert(ShaderWarning::UNUSED_STRUCT, &used_structs);
+ warnings_check_map.insert(ShaderWarning::UNUSED_UNIFORM, &used_uniforms);
+ warnings_check_map.insert(ShaderWarning::UNUSED_VARYING, &used_varyings);
+
+ warnings_check_map2.insert(ShaderWarning::UNUSED_LOCAL_VARIABLE, &used_local_vars);
+#endif // DEBUG_ENABLED
}
ShaderLanguage::~ShaderLanguage() {
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index e00f4dce19..c82f71d10d 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -39,6 +39,10 @@
#include "core/typedefs.h"
#include "core/variant/variant.h"
+#ifdef DEBUG_ENABLED
+#include "shader_warnings.h"
+#endif // DEBUG_ENABLED
+
class ShaderLanguage {
public:
struct TkPos {
@@ -365,6 +369,8 @@ public:
virtual DataType get_datatype() const { return TYPE_VOID; }
virtual String get_datatype_name() const { return ""; }
+ virtual int get_array_size() const { return 0; }
+ virtual bool is_indexed() const { return false; }
Node(Type t) :
type(t) {}
@@ -384,11 +390,15 @@ public:
struct OperatorNode : public Node {
DataType return_cache = TYPE_VOID;
DataPrecision return_precision_cache = PRECISION_DEFAULT;
+ int return_array_size = 0;
Operator op = OP_EQUAL;
StringName struct_name;
Vector<Node *> arguments;
- virtual DataType get_datatype() const { return return_cache; }
- virtual String get_datatype_name() const { return String(struct_name); }
+
+ virtual DataType get_datatype() const override { return return_cache; }
+ virtual String get_datatype_name() const override { return String(struct_name); }
+ virtual int get_array_size() const override { return return_array_size; }
+ virtual bool is_indexed() const override { return op == OP_INDEX; }
OperatorNode() :
Node(TYPE_OPERATOR) {}
@@ -398,9 +408,11 @@ public:
DataType datatype_cache = TYPE_VOID;
StringName name;
StringName struct_name;
- virtual DataType get_datatype() const { return datatype_cache; }
- virtual String get_datatype_name() const { return String(struct_name); }
bool is_const = false;
+ bool is_local = false;
+
+ virtual DataType get_datatype() const override { return datatype_cache; }
+ virtual String get_datatype_name() const override { return String(struct_name); }
VariableNode() :
Node(TYPE_VARIABLE) {}
@@ -416,9 +428,9 @@ public:
StringName name;
Node *initializer;
};
-
Vector<Declaration> declarations;
- virtual DataType get_datatype() const { return datatype; }
+
+ virtual DataType get_datatype() const override { return datatype; }
VariableDeclarationNode() :
Node(TYPE_VARIABLE_DECLARATION) {}
@@ -432,9 +444,13 @@ public:
Node *call_expression = nullptr;
Node *assign_expression = nullptr;
bool is_const = false;
+ int array_size = 0;
+ bool is_local = false;
- virtual DataType get_datatype() const { return datatype_cache; }
- virtual String get_datatype_name() const { return String(struct_name); }
+ virtual DataType get_datatype() const override { return datatype_cache; }
+ virtual String get_datatype_name() const override { return String(struct_name); }
+ virtual int get_array_size() const override { return (index_expression || call_expression) ? 0 : array_size; }
+ virtual bool is_indexed() const override { return index_expression != nullptr; }
ArrayNode() :
Node(TYPE_ARRAY) {}
@@ -445,6 +461,10 @@ public:
String struct_name;
Vector<Node *> initializer;
+ virtual DataType get_datatype() const override { return datatype; }
+ virtual String get_datatype_name() const override { return struct_name; }
+ virtual int get_array_size() const override { return initializer.size(); }
+
ArrayConstructNode() :
Node(TYPE_ARRAY_CONSTRUCT) {}
};
@@ -460,10 +480,11 @@ public:
StringName name;
uint32_t size;
Vector<Node *> initializer;
+ bool single_expression;
};
-
Vector<Declaration> declarations;
- virtual DataType get_datatype() const { return datatype; }
+
+ virtual DataType get_datatype() const override { return datatype; }
ArrayDeclarationNode() :
Node(TYPE_ARRAY_DECLARATION) {}
@@ -483,8 +504,10 @@ public:
Vector<Value> values;
Vector<ArrayDeclarationNode::Declaration> array_declarations;
- virtual DataType get_datatype() const { return datatype; }
- virtual String get_datatype_name() const { return struct_name; }
+
+ virtual DataType get_datatype() const override { return datatype; }
+ virtual String get_datatype_name() const override { return struct_name; }
+ virtual int get_array_size() const override { return array_size; }
ConstantNode() :
Node(TYPE_CONSTANT) {}
@@ -546,10 +569,13 @@ public:
Node *owner = nullptr;
Node *index_expression = nullptr;
Node *assign_expression = nullptr;
+ Node *call_expression = nullptr;
bool has_swizzling_duplicates = false;
- virtual DataType get_datatype() const { return datatype; }
- virtual String get_datatype_name() const { return String(struct_name); }
+ virtual DataType get_datatype() const override { return datatype; }
+ virtual String get_datatype_name() const override { return String(struct_name); }
+ virtual int get_array_size() const override { return array_size; }
+ virtual bool is_indexed() const override { return index_expression != nullptr || call_expression != nullptr; }
MemberNode() :
Node(TYPE_MEMBER) {}
@@ -575,6 +601,7 @@ public:
bool tex_builtin_check;
StringName tex_builtin;
bool is_const;
+ int array_size;
Map<StringName, Set<int>> tex_argument_connect;
};
@@ -583,10 +610,15 @@ public:
DataType return_type = TYPE_VOID;
StringName return_struct_name;
DataPrecision return_precision = PRECISION_DEFAULT;
+ int return_array_size = 0;
Vector<Argument> arguments;
BlockNode *body = nullptr;
bool can_discard = false;
+ virtual DataType get_datatype() const override { return return_type; }
+ virtual String get_datatype_name() const override { return String(return_struct_name); }
+ virtual int get_array_size() const override { return return_array_size; }
+
FunctionNode() :
Node(TYPE_FUNCTION) {}
};
@@ -616,10 +648,9 @@ public:
struct Varying {
enum Stage {
STAGE_UNKNOWN,
- STAGE_VERTEX, // transition stage to STAGE_VERTEX_TO_FRAGMENT or STAGE_VERTEX_TO_LIGHT, emits error if they are not used
- STAGE_FRAGMENT, // transition stage to STAGE_FRAGMENT_TO_LIGHT, emits error if it's not used
- STAGE_VERTEX_TO_FRAGMENT,
- STAGE_VERTEX_TO_LIGHT,
+ STAGE_VERTEX, // transition stage to STAGE_VERTEX_TO_FRAGMENT_LIGHT, emits warning if it's not used
+ STAGE_FRAGMENT, // transition stage to STAGE_FRAGMENT_TO_LIGHT, emits warning if it's not used
+ STAGE_VERTEX_TO_FRAGMENT_LIGHT,
STAGE_FRAGMENT_TO_LIGHT,
};
@@ -661,8 +692,10 @@ public:
int order = 0;
int texture_order = 0;
+ int texture_binding = 0;
DataType type = TYPE_VOID;
DataPrecision precision = PRECISION_DEFAULT;
+ int array_size = 0;
Vector<ConstantNode::Value> default_value;
Scope scope = SCOPE_LOCAL;
Hint hint = HINT_NONE;
@@ -737,13 +770,15 @@ public:
static String get_datatype_name(DataType p_type);
static bool is_token_nonvoid_datatype(TokenType p_type);
static bool is_token_operator(TokenType p_type);
+ static bool is_token_operator_assign(TokenType p_type);
static bool convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value = nullptr);
static DataType get_scalar_type(DataType p_type);
static int get_cardinality(DataType p_type);
static bool is_scalar_type(DataType p_type);
+ static bool is_float_type(DataType p_type);
static bool is_sampler_type(DataType p_type);
- static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
+ static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform);
static uint32_t get_type_size(DataType p_type);
@@ -802,15 +837,57 @@ private:
String error_str;
int error_line;
+#ifdef DEBUG_ENABLED
+ struct Usage {
+ int decl_line;
+ bool used = false;
+ Usage(int p_decl_line = -1) {
+ decl_line = p_decl_line;
+ }
+ };
+
+ Map<StringName, Usage> used_constants;
+ Map<StringName, Usage> used_varyings;
+ Map<StringName, Usage> used_uniforms;
+ Map<StringName, Usage> used_functions;
+ Map<StringName, Usage> used_structs;
+ Map<ShaderWarning::Code, Map<StringName, Usage> *> warnings_check_map;
+
+ Map<StringName, Map<StringName, Usage>> used_local_vars;
+ Map<ShaderWarning::Code, Map<StringName, Map<StringName, Usage>> *> warnings_check_map2;
+
+ List<ShaderWarning> warnings;
+
+ bool check_warnings = false;
+ uint32_t warning_flags;
+
+ void _add_line_warning(ShaderWarning::Code p_code, const StringName &p_subject = "") {
+ warnings.push_back(ShaderWarning(p_code, tk_line, p_subject));
+ }
+ void _add_warning(ShaderWarning::Code p_code, int p_line, const StringName &p_subject = "") {
+ warnings.push_back(ShaderWarning(p_code, p_line, p_subject));
+ }
+ void _check_warning_accums();
+#endif // DEBUG_ENABLED
+
String code;
int char_idx;
int tk_line;
StringName current_function;
bool last_const = false;
+ StringName last_name;
VaryingFunctionNames varying_function_names;
+ struct VaryingUsage {
+ ShaderNode::Varying *var;
+ int line;
+ };
+ List<VaryingUsage> unknown_varying_usages;
+
+ bool _check_varying_usages(int *r_error_line, String *r_error_message) const;
+
TkPos _get_tkpos() {
TkPos tkp;
tkp.char_idx = char_idx;
@@ -848,25 +925,40 @@ private:
IDENTIFIER_LOCAL_VAR,
IDENTIFIER_BUILTIN_VAR,
IDENTIFIER_CONSTANT,
+ IDENTIFIER_MAX,
};
+ IdentifierType last_type = IDENTIFIER_MAX;
+
bool _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr, ConstantNode::Value *r_constant_value = nullptr);
+#ifdef DEBUG_ENABLED
+ void _parse_used_identifier(const StringName &p_identifier, IdentifierType p_type, const StringName &p_function);
+#endif // DEBUG_ENABLED
bool _is_operator_assign(Operator p_op) const;
bool _validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message = nullptr);
- bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr);
+ bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr, int *r_ret_size = nullptr);
struct BuiltinFuncDef {
enum { MAX_ARGS = 5 };
const char *name;
DataType rettype;
const DataType args[MAX_ARGS];
+ const char *args_names[MAX_ARGS];
SubClassTag tag;
bool high_end;
};
struct BuiltinFuncOutArgs { //arguments used as out in built in functions
+ enum { MAX_ARGS = 2 };
+ const char *name;
+ const int arguments[MAX_ARGS];
+ };
+
+ struct BuiltinFuncConstArgs {
const char *name;
- int argument;
+ int arg;
+ int min;
+ int max;
};
CompletionType completion_type;
@@ -882,9 +974,11 @@ private:
bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier);
static const BuiltinFuncDef builtin_func_defs[];
static const BuiltinFuncOutArgs builtin_func_out_args[];
+ static const BuiltinFuncConstArgs builtin_func_const_args[];
Error _validate_datatype(DataType p_type);
- bool _compare_datatypes_in_nodes(Node *a, Node *b) const;
+ bool _compare_datatypes(DataType p_datatype_a, String p_datatype_name_a, int p_array_size_a, DataType p_datatype_b, String p_datatype_name_b, int p_array_size_b);
+ bool _compare_datatypes_in_nodes(Node *a, Node *b);
bool _validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str);
bool _parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg = nullptr);
@@ -894,7 +988,12 @@ private:
bool _validate_varying_using(ShaderNode::Varying &p_varying, String *r_message);
bool _check_node_constness(const Node *p_node) const;
+ Node *_parse_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, int &r_array_size);
+ Error _parse_global_array_size(int &r_array_size);
+ Error _parse_local_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, ArrayDeclarationNode *p_node, ArrayDeclarationNode::Declaration *p_decl, int &r_array_size, bool &r_is_unknown_size);
+
Node *_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info);
+ Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info);
Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size);
ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node);
@@ -909,6 +1008,16 @@ private:
Error _find_last_flow_op_in_op(ControlFlowNode *p_flow, FlowOperation p_op);
public:
+#ifdef DEBUG_ENABLED
+ List<ShaderWarning>::Element *get_warnings_ptr();
+
+ void enable_warning_checking(bool p_enabled);
+ bool is_warning_checking_enabled() const;
+
+ void set_warning_flags(uint32_t p_flags);
+ uint32_t get_warning_flags() const;
+#endif // DEBUG_ENABLED
+
//static void get_keyword_list(ShaderType p_type,List<String> *p_keywords);
void clear();
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 0bf68b9e0f..10786555db 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -29,19 +29,24 @@
/*************************************************************************/
#include "shader_types.h"
+#include "core/math/math_defs.h"
-const Map<StringName, ShaderLanguage::FunctionInfo> &ShaderTypes::get_functions(RS::ShaderMode p_mode) {
+const Map<StringName, ShaderLanguage::FunctionInfo> &ShaderTypes::get_functions(RS::ShaderMode p_mode) const {
return shader_modes[p_mode].functions;
}
-const Vector<StringName> &ShaderTypes::get_modes(RS::ShaderMode p_mode) {
+const Vector<StringName> &ShaderTypes::get_modes(RS::ShaderMode p_mode) const {
return shader_modes[p_mode].modes;
}
-const Set<String> &ShaderTypes::get_types() {
+const Set<String> &ShaderTypes::get_types() const {
return shader_types;
}
+const List<String> &ShaderTypes::get_types_list() const {
+ return shader_types_list;
+}
+
ShaderTypes *ShaderTypes::singleton = nullptr;
static ShaderLanguage::BuiltInInfo constt(ShaderLanguage::DataType p_type) {
@@ -54,6 +59,9 @@ ShaderTypes::ShaderTypes() {
/*************** SPATIAL ***********************/
shader_modes[RS::SHADER_SPATIAL].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SPATIAL].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SPATIAL].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SPATIAL].functions["global"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC3;
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3;
@@ -88,6 +96,10 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_INDEX"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_MONO_LEFT"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT);
+
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VERTEX"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["FRONT_FACING"] = constt(ShaderLanguage::TYPE_BOOL);
@@ -114,19 +126,22 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_STRENGTH"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_COLOR"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_DEPTH"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_CURVE"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_BOOST"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["BACKLIGHT"] = ShaderLanguage::TYPE_VEC3;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO_LIGHT_AFFECT"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["EMISSION"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D;
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL_ROUGHNESS_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D;
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL_ROUGHNESS_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = ShaderLanguage::TYPE_VEC2;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_INDEX"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_MONO_LEFT"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT);
+
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
@@ -200,7 +215,6 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_lambert");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_lambert_wrap");
- shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_oren_nayar");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_burley");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_toon");
@@ -227,6 +241,9 @@ ShaderTypes::ShaderTypes() {
/************ CANVAS ITEM **************************/
shader_modes[RS::SHADER_CANVAS_ITEM].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["global"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC2;
shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["UV"] = ShaderLanguage::TYPE_VEC2;
@@ -317,12 +334,14 @@ ShaderTypes::ShaderTypes() {
/************ PARTICLES **************************/
shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3;
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL;
- shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4;
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT);
@@ -348,7 +367,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT);
@@ -381,6 +400,9 @@ ShaderTypes::ShaderTypes() {
/************ SKY **************************/
shader_modes[RS::SHADER_SKY].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_SKY].functions["global"].built_ins["POSITION"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_SKY].functions["global"].built_ins["RADIANCE"] = constt(ShaderLanguage::TYPE_SAMPLERCUBE);
shader_modes[RS::SHADER_SKY].functions["global"].built_ins["AT_HALF_RES_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
@@ -421,8 +443,31 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SKY].modes.push_back("use_quarter_res_pass");
shader_modes[RS::SHADER_SKY].modes.push_back("disable_fog");
- shader_types.insert("spatial");
- shader_types.insert("canvas_item");
- shader_types.insert("particles");
- shader_types.insert("sky");
+ /************ FOG **************************/
+
+ shader_modes[RS::SHADER_FOG].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_FOG].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_FOG].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_FOG].functions["global"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT);
+
+ shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["WORLD_POSITION"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["OBJECT_POSITION"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["UVW"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["EXTENTS"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["SDF"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["ALBEDO"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["DENSITY"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["EMISSION"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_FOG].functions["fog"].main_function = true;
+
+ shader_types_list.push_back("spatial");
+ shader_types_list.push_back("canvas_item");
+ shader_types_list.push_back("particles");
+ shader_types_list.push_back("sky");
+ shader_types_list.push_back("fog");
+
+ for (int i = 0; i < shader_types_list.size(); i++) {
+ shader_types.insert(shader_types_list[i]);
+ }
}
diff --git a/servers/rendering/shader_types.h b/servers/rendering/shader_types.h
index e59cef6b79..75a310a1b1 100644
--- a/servers/rendering/shader_types.h
+++ b/servers/rendering/shader_types.h
@@ -46,13 +46,15 @@ class ShaderTypes {
static ShaderTypes *singleton;
Set<String> shader_types;
+ List<String> shader_types_list;
public:
static ShaderTypes *get_singleton() { return singleton; }
- const Map<StringName, ShaderLanguage::FunctionInfo> &get_functions(RS::ShaderMode p_mode);
- const Vector<StringName> &get_modes(RS::ShaderMode p_mode);
- const Set<String> &get_types();
+ const Map<StringName, ShaderLanguage::FunctionInfo> &get_functions(RS::ShaderMode p_mode) const;
+ const Vector<StringName> &get_modes(RS::ShaderMode p_mode) const;
+ const Set<String> &get_types() const;
+ const List<String> &get_types_list() const;
ShaderTypes();
};
diff --git a/servers/rendering/shader_warnings.cpp b/servers/rendering/shader_warnings.cpp
new file mode 100644
index 0000000000..0b8476478c
--- /dev/null
+++ b/servers/rendering/shader_warnings.cpp
@@ -0,0 +1,135 @@
+/*************************************************************************/
+/* shader_warnings.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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. */
+/*************************************************************************/
+
+#include "shader_warnings.h"
+#include "core/variant/variant.h"
+
+#ifdef DEBUG_ENABLED
+
+ShaderWarning::Code ShaderWarning::get_code() const {
+ return code;
+}
+
+int ShaderWarning::get_line() const {
+ return line;
+}
+
+const StringName &ShaderWarning::get_subject() const {
+ return subject;
+}
+
+String ShaderWarning::get_message() const {
+ switch (code) {
+ case FLOAT_COMPARISON:
+ return vformat("Direct floating-point comparison (this may not evaluate to `true` as you expect). Instead, use `abs(a - b) < 0.0001` for an approximate but predictable comparison.");
+ case UNUSED_CONSTANT:
+ return vformat("The const '%s' is declared but never used.", subject);
+ case UNUSED_FUNCTION:
+ return vformat("The function '%s' is declared but never used.", subject);
+ case UNUSED_STRUCT:
+ return vformat("The struct '%s' is declared but never used.", subject);
+ case UNUSED_UNIFORM:
+ return vformat("The uniform '%s' is declared but never used.", subject);
+ case UNUSED_VARYING:
+ return vformat("The varying '%s' is declared but never used.", subject);
+ case UNUSED_LOCAL_VARIABLE:
+ return vformat("The local variable '%s' is declared but never used.", subject);
+ default:
+ break;
+ }
+ return String();
+}
+
+String ShaderWarning::get_name() const {
+ return get_name_from_code(code);
+}
+
+String ShaderWarning::get_name_from_code(Code p_code) {
+ ERR_FAIL_INDEX_V(p_code, WARNING_MAX, String());
+
+ static const char *names[] = {
+ "FLOAT_COMPARISON",
+ "UNUSED_CONSTANT",
+ "UNUSED_FUNCTION",
+ "UNUSED_STRUCT",
+ "UNUSED_UNIFORM",
+ "UNUSED_VARYING",
+ "UNUSED_LOCAL_VARIABLE",
+ };
+
+ static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names.");
+
+ return names[(int)p_code];
+}
+
+ShaderWarning::Code ShaderWarning::get_code_from_name(const String &p_name) {
+ for (int i = 0; i < WARNING_MAX; i++) {
+ if (get_name_from_code((Code)i) == p_name) {
+ return (Code)i;
+ }
+ }
+
+ ERR_FAIL_V_MSG(WARNING_MAX, "Invalid shader warning name: " + p_name);
+}
+
+static Map<int, uint32_t> *code_to_flags_map = nullptr;
+
+static void init_code_to_flags_map() {
+ code_to_flags_map = memnew((Map<int, uint32_t>));
+ code_to_flags_map->insert(ShaderWarning::FLOAT_COMPARISON, ShaderWarning::FLOAT_COMPARISON_FLAG);
+ code_to_flags_map->insert(ShaderWarning::UNUSED_CONSTANT, ShaderWarning::UNUSED_CONSTANT_FLAG);
+ code_to_flags_map->insert(ShaderWarning::UNUSED_FUNCTION, ShaderWarning::UNUSED_FUNCTION_FLAG);
+ code_to_flags_map->insert(ShaderWarning::UNUSED_STRUCT, ShaderWarning::UNUSED_STRUCT_FLAG);
+ code_to_flags_map->insert(ShaderWarning::UNUSED_UNIFORM, ShaderWarning::UNUSED_UNIFORM_FLAG);
+ code_to_flags_map->insert(ShaderWarning::UNUSED_VARYING, ShaderWarning::UNUSED_VARYING_FLAG);
+ code_to_flags_map->insert(ShaderWarning::UNUSED_LOCAL_VARIABLE, ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG);
+}
+
+ShaderWarning::CodeFlags ShaderWarning::get_flags_from_codemap(const Map<Code, bool> &p_map) {
+ uint32_t result = 0U;
+
+ if (code_to_flags_map == nullptr) {
+ init_code_to_flags_map();
+ }
+
+ for (const KeyValue<Code, bool> &E : p_map) {
+ if (E.value) {
+ ERR_FAIL_COND_V(!code_to_flags_map->has((int)E.key), ShaderWarning::NONE_FLAG);
+ result |= (*code_to_flags_map)[(int)E.key];
+ }
+ }
+ return (CodeFlags)result;
+}
+
+ShaderWarning::ShaderWarning(Code p_code, int p_line, const StringName &p_subject) :
+ code(p_code), line(p_line), subject(p_subject) {
+}
+
+#endif // DEBUG_ENABLED
diff --git a/servers/rendering/shader_warnings.h b/servers/rendering/shader_warnings.h
new file mode 100644
index 0000000000..db872d8fb1
--- /dev/null
+++ b/servers/rendering/shader_warnings.h
@@ -0,0 +1,85 @@
+/*************************************************************************/
+/* shader_warnings.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 SHADER_WARNINGS
+#define SHADER_WARNINGS
+
+#ifdef DEBUG_ENABLED
+
+#include "core/string/string_name.h"
+#include "core/templates/list.h"
+#include "core/templates/map.h"
+
+class ShaderWarning {
+public:
+ enum Code {
+ FLOAT_COMPARISON,
+ UNUSED_CONSTANT,
+ UNUSED_FUNCTION,
+ UNUSED_STRUCT,
+ UNUSED_UNIFORM,
+ UNUSED_VARYING,
+ UNUSED_LOCAL_VARIABLE,
+ WARNING_MAX,
+ };
+
+ enum CodeFlags : uint32_t {
+ NONE_FLAG = 0U,
+ FLOAT_COMPARISON_FLAG = 1U,
+ UNUSED_CONSTANT_FLAG = 2U,
+ UNUSED_FUNCTION_FLAG = 4U,
+ UNUSED_STRUCT_FLAG = 8U,
+ UNUSED_UNIFORM_FLAG = 16U,
+ UNUSED_VARYING_FLAG = 32U,
+ UNUSED_LOCAL_VARIABLE_FLAG = 64U,
+ };
+
+private:
+ Code code;
+ int line;
+ StringName subject;
+
+public:
+ Code get_code() const;
+ int get_line() const;
+ const StringName &get_subject() const;
+ String get_message() const;
+ String get_name() const;
+
+ static String get_name_from_code(Code p_code);
+ static Code get_code_from_name(const String &p_name);
+ static CodeFlags get_flags_from_codemap(const Map<Code, bool> &p_map);
+
+ ShaderWarning(Code p_code = WARNING_MAX, int p_line = -1, const StringName &p_subject = "");
+};
+
+#endif // DEBUG_ENABLED
+
+#endif // SHADER_WARNINGS