feat: godot-engine-source-4.3-stable

This commit is contained in:
Jan van der Weide 2025-01-17 16:36:38 +01:00
parent c59a7dcade
commit 7125d019b5
11149 changed files with 5070401 additions and 0 deletions

View file

@ -0,0 +1,9 @@
#!/usr/bin/env python
Import("env")
env.add_source_files(env.servers_sources, "*.cpp")
SConscript("dummy/SCsub")
SConscript("renderer_rd/SCsub")
SConscript("storage/SCsub")

View file

@ -0,0 +1,7 @@
#!/usr/bin/env python
Import("env")
env.add_source_files(env.servers_sources, "*.cpp")
SConscript("storage/SCsub")

View file

@ -0,0 +1,55 @@
/**************************************************************************/
/* fog.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 FOG_DUMMY_H
#define FOG_DUMMY_H
#include "servers/rendering/environment/renderer_fog.h"
namespace RendererDummy {
class Fog : public RendererFog {
public:
/* FOG VOLUMES */
virtual RID fog_volume_allocate() override { return RID(); }
virtual void fog_volume_initialize(RID p_rid) override {}
virtual void fog_volume_free(RID p_rid) override {}
virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override {}
virtual void fog_volume_set_size(RID p_fog_volume, const Vector3 &p_size) override {}
virtual void fog_volume_set_material(RID p_fog_volume, RID p_material) override {}
virtual AABB fog_volume_get_aabb(RID p_fog_volume) const override { return AABB(); }
virtual RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const override { return RS::FOG_VOLUME_SHAPE_BOX; }
};
} // namespace RendererDummy
#endif // FOG_DUMMY_H

View file

@ -0,0 +1,87 @@
/**************************************************************************/
/* gi.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 GI_DUMMY_H
#define GI_DUMMY_H
#include "servers/rendering/environment/renderer_gi.h"
namespace RendererDummy {
class GI : public RendererGI {
public:
/* VOXEL GI API */
virtual RID voxel_gi_allocate() override { return RID(); }
virtual void voxel_gi_free(RID p_rid) override {}
virtual void voxel_gi_initialize(RID p_rid) override {}
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) override {}
virtual AABB voxel_gi_get_bounds(RID p_voxel_gi) const override { return AABB(); }
virtual Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const override { return Vector3i(); }
virtual Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const override { return Vector<uint8_t>(); }
virtual Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const override { return Vector<uint8_t>(); }
virtual Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const override { return Vector<uint8_t>(); }
virtual Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const override { return Vector<int>(); }
virtual Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const override { return Transform3D(); }
virtual void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) override {}
virtual float voxel_gi_get_dynamic_range(RID p_voxel_gi) const override { return 0; }
virtual void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) override {}
virtual float voxel_gi_get_propagation(RID p_voxel_gi) const override { return 0; }
virtual void voxel_gi_set_energy(RID p_voxel_gi, float p_range) override {}
virtual float voxel_gi_get_energy(RID p_voxel_gi) const override { return 0.0; }
virtual void voxel_gi_set_baked_exposure_normalization(RID p_voxel_gi, float p_baked_exposure) override {}
virtual float voxel_gi_get_baked_exposure_normalization(RID p_voxel_gi) const override { return 1.0; }
virtual void voxel_gi_set_bias(RID p_voxel_gi, float p_range) override {}
virtual float voxel_gi_get_bias(RID p_voxel_gi) const override { return 0.0; }
virtual void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) override {}
virtual float voxel_gi_get_normal_bias(RID p_voxel_gi) const override { return 0.0; }
virtual void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) override {}
virtual bool voxel_gi_is_interior(RID p_voxel_gi) const override { return false; }
virtual void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) override {}
virtual bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const override { return false; }
virtual uint32_t voxel_gi_get_version(RID p_voxel_gi) const override { return 0; }
virtual void sdfgi_reset() override {}
};
} // namespace RendererDummy
#endif // GI_DUMMY_H

View file

@ -0,0 +1,64 @@
/**************************************************************************/
/* rasterizer_canvas_dummy.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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_CANVAS_DUMMY_H
#define RASTERIZER_CANVAS_DUMMY_H
#include "servers/rendering/renderer_canvas_render.h"
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, RenderingMethod::RenderInfo *r_render_info = nullptr) 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 {}
virtual void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) override {}
RasterizerCanvasDummy() {}
~RasterizerCanvasDummy() {}
};
#endif // RASTERIZER_CANVAS_DUMMY_H

View file

@ -0,0 +1,118 @@
/**************************************************************************/
/* rasterizer_dummy.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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/templates/rid_owner.h"
#include "core/templates/self_list.h"
#include "scene/resources/mesh.h"
#include "servers/rendering/dummy/environment/fog.h"
#include "servers/rendering/dummy/environment/gi.h"
#include "servers/rendering/dummy/rasterizer_canvas_dummy.h"
#include "servers/rendering/dummy/rasterizer_scene_dummy.h"
#include "servers/rendering/dummy/storage/light_storage.h"
#include "servers/rendering/dummy/storage/material_storage.h"
#include "servers/rendering/dummy/storage/mesh_storage.h"
#include "servers/rendering/dummy/storage/particles_storage.h"
#include "servers/rendering/dummy/storage/texture_storage.h"
#include "servers/rendering/dummy/storage/utilities.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering_server.h"
class RasterizerDummy : public RendererCompositor {
private:
uint64_t frame = 1;
double delta = 0;
double time = 0.0;
protected:
RasterizerCanvasDummy canvas;
RendererDummy::Utilities utilities;
RendererDummy::LightStorage light_storage;
RendererDummy::MaterialStorage material_storage;
RendererDummy::MeshStorage mesh_storage;
RendererDummy::ParticlesStorage particles_storage;
RendererDummy::TextureStorage texture_storage;
RendererDummy::GI gi;
RendererDummy::Fog fog;
RasterizerSceneDummy scene;
public:
RendererUtilities *get_utilities() override { return &utilities; };
RendererLightStorage *get_light_storage() override { return &light_storage; };
RendererMaterialStorage *get_material_storage() override { return &material_storage; };
RendererMeshStorage *get_mesh_storage() override { return &mesh_storage; };
RendererParticlesStorage *get_particles_storage() override { return &particles_storage; };
RendererTextureStorage *get_texture_storage() override { return &texture_storage; };
RendererGI *get_gi() override { return &gi; };
RendererFog *get_fog() override { return &fog; };
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;
time += frame_step;
}
void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) override {}
void gl_end_frame(bool p_swap_buffers) 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;
low_end = false;
}
uint64_t get_frame_number() const override { return frame; }
double get_frame_delta_time() const override { return delta; }
double get_total_time() const override { return time; }
RasterizerDummy() {}
~RasterizerDummy() {}
};
#endif // RASTERIZER_DUMMY_H

View file

@ -0,0 +1,194 @@
/**************************************************************************/
/* rasterizer_scene_dummy.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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_SCENE_DUMMY_H
#define RASTERIZER_SCENE_DUMMY_H
#include "core/templates/paged_allocator.h"
#include "servers/rendering/renderer_scene_render.h"
#include "storage/utilities.h"
class RasterizerSceneDummy : public RendererSceneRender {
public:
class GeometryInstanceDummy : public RenderGeometryInstance {
public:
GeometryInstanceDummy() {}
virtual void _mark_dirty() override {}
virtual void set_skeleton(RID p_skeleton) override {}
virtual void set_material_override(RID p_override) override {}
virtual void set_material_overlay(RID p_overlay) override {}
virtual void set_surface_materials(const Vector<RID> &p_materials) override {}
virtual void set_mesh_instance(RID p_mesh_instance) override {}
virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override {}
virtual void set_pivot_data(float p_sorting_offset, bool p_use_aabb_center) override {}
virtual void set_lod_bias(float p_lod_bias) override {}
virtual void set_layer_mask(uint32_t p_layer_mask) override {}
virtual void set_fade_range(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 set_parent_fade_alpha(float p_alpha) override {}
virtual void set_transparency(float p_transparency) override {}
virtual void set_use_baked_light(bool p_enable) override {}
virtual void set_use_dynamic_gi(bool p_enable) override {}
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override {}
virtual void set_lightmap_capture(const Color *p_sh9) override {}
virtual void set_instance_shader_uniforms_offset(int32_t p_offset) override {}
virtual void set_cast_double_sided_shadows(bool p_enable) override {}
virtual Transform3D get_transform() override { return Transform3D(); }
virtual AABB get_aabb() override { return AABB(); }
virtual void pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) override {}
virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {}
virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {}
virtual void pair_voxel_gi_instances(const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override {}
virtual void set_softshadow_projector_pairing(bool p_softshadow, bool p_projector) override {}
};
PagedAllocator<GeometryInstanceDummy> geometry_instance_alloc;
public:
RenderGeometryInstance *geometry_instance_create(RID p_base) override {
RS::InstanceType type = RendererDummy::Utilities::get_singleton()->get_base_type(p_base);
ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr);
GeometryInstanceDummy *ginstance = geometry_instance_alloc.alloc();
return ginstance;
}
void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) override {
GeometryInstanceDummy *ginstance = static_cast<GeometryInstanceDummy *>(p_geometry_instance);
ERR_FAIL_NULL(ginstance);
geometry_instance_alloc.free(ginstance);
}
uint32_t geometry_instance_get_pair_mask() override { return 0; }
/* SDFGI UPDATE */
void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}
int sdfgi_get_pending_region_count(const Ref<RenderSceneBuffers> &p_render_buffers) const override { return 0; }
AABB sdfgi_get_pending_region_bounds(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override { return AABB(); }
uint32_t sdfgi_get_pending_region_cascade(const Ref<RenderSceneBuffers> &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 */
void environment_glow_set_use_bicubic_upscale(bool p_enable) override {}
void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) 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_ssil_quality(RS::EnvironmentSSILQuality 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_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_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>(); }
void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override {}
void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) 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 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<RenderGeometryInstance *> &p_dynamic_objects) override {}
void voxel_gi_set_quality(RS::VoxelGIQuality) override {}
void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &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_attributes, RID p_compositor, 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_mesh_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, RenderingMethod::RenderInfo *r_info = nullptr) override {}
void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override {}
void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &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 {}
Ref<RenderSceneBuffers> render_buffers_create() override { return Ref<RenderSceneBuffers>(); }
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 TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) override { return TypedArray<Image>(); }
bool free(RID p_rid) override {
if (is_environment(p_rid)) {
environment_free(p_rid);
return true;
} else if (is_compositor(p_rid)) {
compositor_free(p_rid);
return true;
} else if (is_compositor_effect(p_rid)) {
compositor_effect_free(p_rid);
return true;
} else if (RSG::camera_attributes->owns_camera_attributes(p_rid)) {
RSG::camera_attributes->camera_attributes_free(p_rid);
return true;
} else {
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() {}
};
#endif // RASTERIZER_SCENE_DUMMY_H

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
Import("env")
env.add_source_files(env.servers_sources, "*.cpp")

View file

@ -0,0 +1,86 @@
/**************************************************************************/
/* light_storage.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "light_storage.h"
using namespace RendererDummy;
LightStorage *LightStorage::singleton = nullptr;
LightStorage *LightStorage::get_singleton() {
return singleton;
}
LightStorage::LightStorage() {
singleton = this;
}
LightStorage::~LightStorage() {
singleton = nullptr;
}
bool LightStorage::free(RID p_rid) {
if (owns_lightmap(p_rid)) {
lightmap_free(p_rid);
return true;
} else if (owns_lightmap_instance(p_rid)) {
lightmap_instance_free(p_rid);
return true;
}
return false;
}
/* LIGHTMAP API */
RID LightStorage::lightmap_allocate() {
return lightmap_owner.allocate_rid();
}
void LightStorage::lightmap_initialize(RID p_lightmap) {
lightmap_owner.initialize_rid(p_lightmap, Lightmap());
}
void LightStorage::lightmap_free(RID p_rid) {
lightmap_set_textures(p_rid, RID(), false);
lightmap_owner.free(p_rid);
}
/* LIGHTMAP INSTANCE */
RID LightStorage::lightmap_instance_create(RID p_lightmap) {
LightmapInstance li;
li.lightmap = p_lightmap;
return lightmap_instance_owner.make_rid(li);
}
void LightStorage::lightmap_instance_free(RID p_lightmap) {
lightmap_instance_owner.free(p_lightmap);
}

View file

@ -0,0 +1,216 @@
/**************************************************************************/
/* light_storage.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 LIGHT_STORAGE_DUMMY_H
#define LIGHT_STORAGE_DUMMY_H
#include "servers/rendering/storage/light_storage.h"
namespace RendererDummy {
class LightStorage : public RendererLightStorage {
private:
static LightStorage *singleton;
/* LIGHTMAP */
struct Lightmap {
// dummy lightmap, no data
};
mutable RID_Owner<Lightmap, true> lightmap_owner;
/* LIGHTMAP INSTANCE */
struct LightmapInstance {
RID lightmap;
};
mutable RID_Owner<LightmapInstance> lightmap_instance_owner;
public:
static LightStorage *get_singleton();
LightStorage();
virtual ~LightStorage();
bool free(RID p_rid);
/* Light API */
virtual RID directional_light_allocate() override { return RID(); }
virtual void directional_light_initialize(RID p_rid) override {}
virtual RID omni_light_allocate() override { return RID(); }
virtual void omni_light_initialize(RID p_rid) override {}
virtual RID spot_light_allocate() override { return RID(); }
virtual void spot_light_initialize(RID p_rid) override {}
virtual void light_free(RID p_rid) override {}
virtual void light_set_color(RID p_light, const Color &p_color) override {}
virtual void light_set_param(RID p_light, RS::LightParam p_param, float p_value) override {}
virtual void light_set_shadow(RID p_light, bool p_enabled) override {}
virtual void light_set_projector(RID p_light, RID p_texture) override {}
virtual void light_set_negative(RID p_light, bool p_enable) override {}
virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) override {}
virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) override {}
virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override {}
virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override {}
virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override {}
virtual void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) override {}
virtual void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) override {}
virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) override {}
virtual bool light_directional_get_blend_splits(RID p_light) const override { return false; }
virtual void light_directional_set_sky_mode(RID p_light, RS::LightDirectionalSkyMode p_mode) override {}
virtual RS::LightDirectionalSkyMode light_directional_get_sky_mode(RID p_light) const override { return RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_AND_SKY; }
virtual RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) override { return RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; }
virtual RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) override { return RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; }
virtual bool light_has_shadow(RID p_light) const override { return false; }
virtual bool light_has_projector(RID p_light) const override { return false; }
virtual RS::LightType light_get_type(RID p_light) const override { return RS::LIGHT_OMNI; }
virtual AABB light_get_aabb(RID p_light) const override { return AABB(); }
virtual float light_get_param(RID p_light, RS::LightParam p_param) override { return 0.0; }
virtual Color light_get_color(RID p_light) override { return Color(); }
virtual bool light_get_reverse_cull_face_mode(RID p_light) const override { return false; }
virtual RS::LightBakeMode light_get_bake_mode(RID p_light) override { return RS::LIGHT_BAKE_DISABLED; }
virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) override { return 0; }
virtual uint64_t light_get_version(RID p_light) const override { return 0; }
virtual uint32_t light_get_cull_mask(RID p_light) const override { return 0; }
/* LIGHT INSTANCE API */
RID light_instance_create(RID p_light) override { return RID(); }
void light_instance_free(RID p_light) override {}
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 Projection &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 {}
virtual bool light_instance_is_shadow_visible_at_position(RID p_light_instance, const Vector3 &p_position) const override { return false; }
/* PROBE API */
virtual RID reflection_probe_allocate() override { return RID(); }
virtual void reflection_probe_initialize(RID p_rid) override {}
virtual void reflection_probe_free(RID p_rid) override {}
virtual void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) override {}
virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity) override {}
virtual void reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) override {}
virtual void reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) override {}
virtual void reflection_probe_set_ambient_energy(RID p_probe, float p_energy) override {}
virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance) override {}
virtual void reflection_probe_set_size(RID p_probe, const Vector3 &p_size) override {}
virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) override {}
virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) override {}
virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) override {}
virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) override {}
virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) override {}
virtual void reflection_probe_set_reflection_mask(RID p_probe, uint32_t p_layers) override {}
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) override {}
virtual void reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) override {}
virtual float reflection_probe_get_mesh_lod_threshold(RID p_probe) const override { return 0.0; }
virtual AABB reflection_probe_get_aabb(RID p_probe) const override { return AABB(); }
virtual RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const override { return RenderingServer::REFLECTION_PROBE_UPDATE_ONCE; }
virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const override { return 0; }
virtual uint32_t reflection_probe_get_reflection_mask(RID p_probe) const override { return 0; }
virtual Vector3 reflection_probe_get_size(RID p_probe) const override { return Vector3(); }
virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const override { return Vector3(); }
virtual float reflection_probe_get_origin_max_distance(RID p_probe) const override { return 0.0; }
virtual bool reflection_probe_renders_shadows(RID p_probe) const override { return false; }
/* REFLECTION ATLAS */
virtual RID reflection_atlas_create() override { return RID(); }
virtual void reflection_atlas_free(RID p_ref_atlas) override {}
virtual int reflection_atlas_get_size(RID p_ref_atlas) const override { return 0; }
virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override {}
/* REFLECTION PROBE INSTANCE */
virtual RID reflection_probe_instance_create(RID p_probe) override { return RID(); }
virtual void reflection_probe_instance_free(RID p_instance) override {}
virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override {}
virtual bool reflection_probe_has_atlas_index(RID p_instance) override { return false; }
virtual void reflection_probe_release_atlas_index(RID p_instance) override {}
virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override { return false; }
virtual bool reflection_probe_instance_has_reflection(RID p_instance) override { return false; }
virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override { return false; }
virtual Ref<RenderSceneBuffers> reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) override { return Ref<RenderSceneBuffers>(); }
virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override { return true; }
/* LIGHTMAP CAPTURE */
bool owns_lightmap(RID p_rid) { return lightmap_owner.owns(p_rid); }
virtual RID lightmap_allocate() override;
virtual void lightmap_initialize(RID p_rid) override;
virtual void lightmap_free(RID p_rid) override;
virtual void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) override {}
virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) override {}
virtual void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) override {}
virtual 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 {}
virtual void lightmap_set_baked_exposure_normalization(RID p_lightmap, float p_exposure) override {}
virtual PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const override { return PackedVector3Array(); }
virtual PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const override { return PackedColorArray(); }
virtual PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const override { return PackedInt32Array(); }
virtual PackedInt32Array lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const override { return PackedInt32Array(); }
virtual AABB lightmap_get_aabb(RID p_lightmap) const override { return AABB(); }
virtual void lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) override {}
virtual bool lightmap_is_interior(RID p_lightmap) const override { return false; }
virtual void lightmap_set_probe_capture_update_speed(float p_speed) override {}
virtual float lightmap_get_probe_capture_update_speed() const override { return 0; }
/* LIGHTMAP INSTANCE */
bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); }
RID lightmap_instance_create(RID p_lightmap) override;
void lightmap_instance_free(RID p_lightmap) override;
void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override {}
/* SHADOW ATLAS API */
virtual RID shadow_atlas_create() override { return RID(); }
virtual void shadow_atlas_free(RID p_atlas) override {}
virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) 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 { return false; }
virtual void shadow_atlas_update(RID p_atlas) override {}
virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override {}
virtual int get_directional_light_shadow_size(RID p_light_intance) override { return 0; }
virtual void set_directional_shadow_count(int p_count) override {}
};
} // namespace RendererDummy
#endif // LIGHT_STORAGE_DUMMY_H

View file

@ -0,0 +1,137 @@
/**************************************************************************/
/* material_storage.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "material_storage.h"
using namespace RendererDummy;
MaterialStorage *MaterialStorage::singleton = nullptr;
MaterialStorage::MaterialStorage() {
singleton = this;
ShaderCompiler::DefaultIdentifierActions actions;
dummy_compiler.initialize(actions);
}
MaterialStorage::~MaterialStorage() {
singleton = nullptr;
}
RID MaterialStorage::shader_allocate() {
return shader_owner.allocate_rid();
}
void MaterialStorage::shader_initialize(RID p_rid) {
shader_owner.initialize_rid(p_rid, DummyShader());
}
void MaterialStorage::shader_free(RID p_rid) {
DummyShader *shader = shader_owner.get_or_null(p_rid);
ERR_FAIL_NULL(shader);
shader_owner.free(p_rid);
}
void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) {
DummyShader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_NULL(shader);
if (p_code.is_empty()) {
return;
}
String mode_string = ShaderLanguage::get_shader_type(p_code);
RS::ShaderMode new_mode;
if (mode_string == "canvas_item") {
new_mode = RS::SHADER_CANVAS_ITEM;
} else if (mode_string == "particles") {
new_mode = RS::SHADER_PARTICLES;
} else if (mode_string == "spatial") {
new_mode = RS::SHADER_SPATIAL;
} else if (mode_string == "sky") {
new_mode = RS::SHADER_SKY;
} else if (mode_string == "fog") {
new_mode = RS::SHADER_FOG;
} else {
new_mode = RS::SHADER_MAX;
ERR_FAIL_MSG("Shader type " + mode_string + " not supported in Dummy renderer.");
}
ShaderCompiler::IdentifierActions actions;
actions.uniforms = &shader->uniforms;
ShaderCompiler::GeneratedCode gen_code;
Error err = MaterialStorage::get_singleton()->dummy_compiler.compile(new_mode, p_code, &actions, "", gen_code);
ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
}
void MaterialStorage::get_shader_parameter_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
DummyShader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_NULL(shader);
SortArray<Pair<StringName, int>, ShaderLanguage::UniformOrderComparator> sorter;
LocalVector<Pair<StringName, int>> filtered_uniforms;
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : shader->uniforms) {
if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
continue;
}
if (E.value.texture_order >= 0) {
filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.texture_order + 100000));
} else {
filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.order));
}
}
int uniform_count = filtered_uniforms.size();
sorter.sort(filtered_uniforms.ptr(), uniform_count);
String last_group;
for (int i = 0; i < uniform_count; i++) {
const StringName &uniform_name = filtered_uniforms[i].first;
const ShaderLanguage::ShaderNode::Uniform &uniform = shader->uniforms[uniform_name];
String group = uniform.group;
if (!uniform.subgroup.is_empty()) {
group += "::" + uniform.subgroup;
}
if (group != last_group) {
PropertyInfo pi;
pi.usage = PROPERTY_USAGE_GROUP;
pi.name = group;
p_param_list->push_back(pi);
last_group = group;
}
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniform);
pi.name = uniform_name;
p_param_list->push_back(pi);
}
}

View file

@ -0,0 +1,118 @@
/**************************************************************************/
/* material_storage.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 MATERIAL_STORAGE_DUMMY_H
#define MATERIAL_STORAGE_DUMMY_H
#include "servers/rendering/shader_compiler.h"
#include "servers/rendering/shader_language.h"
#include "servers/rendering/storage/material_storage.h"
#include "servers/rendering/storage/utilities.h"
namespace RendererDummy {
class MaterialStorage : public RendererMaterialStorage {
private:
static MaterialStorage *singleton;
struct DummyShader {
HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
};
mutable RID_Owner<DummyShader> shader_owner;
ShaderCompiler dummy_compiler;
public:
static MaterialStorage *get_singleton() { return singleton; }
MaterialStorage();
~MaterialStorage();
/* GLOBAL SHADER UNIFORM API */
virtual void global_shader_parameter_add(const StringName &p_name, RS::GlobalShaderParameterType p_type, const Variant &p_value) override {}
virtual void global_shader_parameter_remove(const StringName &p_name) override {}
virtual Vector<StringName> global_shader_parameter_get_list() const override { return Vector<StringName>(); }
virtual void global_shader_parameter_set(const StringName &p_name, const Variant &p_value) override {}
virtual void global_shader_parameter_set_override(const StringName &p_name, const Variant &p_value) override {}
virtual Variant global_shader_parameter_get(const StringName &p_name) const override { return Variant(); }
virtual RS::GlobalShaderParameterType global_shader_parameter_get_type(const StringName &p_name) const override { return RS::GLOBAL_VAR_TYPE_MAX; }
virtual void global_shader_parameters_load_settings(bool p_load_textures = true) override {}
virtual void global_shader_parameters_clear() override {}
virtual int32_t global_shader_parameters_instance_allocate(RID p_instance) override { return 0; }
virtual void global_shader_parameters_instance_free(RID p_instance) override {}
virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value, int p_flags_count = 0) override {}
/* SHADER API */
bool owns_shader(RID p_rid) { return shader_owner.owns(p_rid); }
virtual RID shader_allocate() override;
virtual void shader_initialize(RID p_rid) override;
virtual void shader_free(RID p_rid) override;
virtual void shader_set_code(RID p_shader, const String &p_code) override;
virtual void shader_set_path_hint(RID p_shader, const String &p_code) override {}
virtual String shader_get_code(RID p_shader) const override { return ""; }
virtual void get_shader_parameter_list(RID p_shader, List<PropertyInfo> *p_param_list) const override;
virtual void shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override {}
virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const override { return RID(); }
virtual Variant shader_get_parameter_default(RID p_material, const StringName &p_param) const override { return Variant(); }
virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override { return RS::ShaderNativeSourceCode(); };
/* MATERIAL API */
virtual RID material_allocate() override { return RID(); }
virtual void material_initialize(RID p_rid) override {}
virtual void material_free(RID p_rid) override{};
virtual void material_set_render_priority(RID p_material, int priority) override {}
virtual void material_set_shader(RID p_shader_material, RID p_shader) override {}
virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) override {}
virtual Variant material_get_param(RID p_material, const StringName &p_param) const override { return Variant(); }
virtual void material_set_next_pass(RID p_material, RID p_next_material) override {}
virtual bool material_is_animated(RID p_material) override { return false; }
virtual bool material_casts_shadows(RID p_material) override { return false; }
virtual void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) override {}
virtual void material_update_dependency(RID p_material, DependencyTracker *p_instance) override {}
};
} // namespace RendererDummy
#endif // MATERIAL_STORAGE_DUMMY_H

View file

@ -0,0 +1,95 @@
/**************************************************************************/
/* mesh_storage.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "mesh_storage.h"
using namespace RendererDummy;
MeshStorage *MeshStorage::singleton = nullptr;
MeshStorage::MeshStorage() {
singleton = this;
}
MeshStorage::~MeshStorage() {
singleton = nullptr;
}
RID MeshStorage::mesh_allocate() {
return mesh_owner.allocate_rid();
}
void MeshStorage::mesh_initialize(RID p_rid) {
mesh_owner.initialize_rid(p_rid, DummyMesh());
}
void MeshStorage::mesh_free(RID p_rid) {
DummyMesh *mesh = mesh_owner.get_or_null(p_rid);
ERR_FAIL_NULL(mesh);
mesh_owner.free(p_rid);
}
void MeshStorage::mesh_clear(RID p_mesh) {
DummyMesh *m = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_NULL(m);
m->surfaces.clear();
}
RID MeshStorage::multimesh_allocate() {
return multimesh_owner.allocate_rid();
}
void MeshStorage::multimesh_initialize(RID p_rid) {
multimesh_owner.initialize_rid(p_rid, DummyMultiMesh());
}
void MeshStorage::multimesh_free(RID p_rid) {
DummyMultiMesh *multimesh = multimesh_owner.get_or_null(p_rid);
ERR_FAIL_NULL(multimesh);
multimesh_owner.free(p_rid);
}
void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
DummyMultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
multimesh->buffer.resize(p_buffer.size());
float *cache_data = multimesh->buffer.ptrw();
memcpy(cache_data, p_buffer.ptr(), p_buffer.size() * sizeof(float));
}
Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
DummyMultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, Vector<float>());
return multimesh->buffer;
}

View file

@ -0,0 +1,200 @@
/**************************************************************************/
/* mesh_storage.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 MESH_STORAGE_DUMMY_H
#define MESH_STORAGE_DUMMY_H
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "servers/rendering/storage/mesh_storage.h"
namespace RendererDummy {
class MeshStorage : public RendererMeshStorage {
private:
static MeshStorage *singleton;
struct DummyMesh {
Vector<RS::SurfaceData> surfaces;
int blend_shape_count;
RS::BlendShapeMode blend_shape_mode;
PackedFloat32Array blend_shape_values;
};
mutable RID_Owner<DummyMesh> mesh_owner;
struct DummyMultiMesh {
PackedFloat32Array buffer;
};
mutable RID_Owner<DummyMultiMesh> multimesh_owner;
public:
static MeshStorage *get_singleton() { return singleton; }
MeshStorage();
~MeshStorage();
/* MESH API */
bool owns_mesh(RID p_rid) { return mesh_owner.owns(p_rid); };
virtual RID mesh_allocate() override;
virtual void mesh_initialize(RID p_rid) override;
virtual void mesh_free(RID p_rid) override;
virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override {}
virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override { return false; }
virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override {
DummyMesh *m = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_NULL(m);
m->surfaces.push_back(RS::SurfaceData());
RS::SurfaceData *s = &m->surfaces.write[m->surfaces.size() - 1];
s->format = p_surface.format;
s->primitive = p_surface.primitive;
s->vertex_data = p_surface.vertex_data;
s->attribute_data = p_surface.attribute_data;
s->vertex_count = p_surface.vertex_count;
s->index_data = p_surface.index_data;
s->index_count = p_surface.index_count;
s->aabb = p_surface.aabb;
s->skin_data = p_surface.skin_data;
s->lods = p_surface.lods;
s->bone_aabbs = p_surface.bone_aabbs;
s->mesh_to_skeleton_xform = p_surface.mesh_to_skeleton_xform;
s->blend_shape_data = p_surface.blend_shape_data;
s->uv_scale = p_surface.uv_scale;
s->material = p_surface.material;
}
virtual int mesh_get_blend_shape_count(RID p_mesh) const override { return 0; }
virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override {}
virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override { return RS::BLEND_SHAPE_MODE_NORMALIZED; }
virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override {}
virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const override { return RID(); }
virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override {
DummyMesh *m = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_NULL_V(m, RS::SurfaceData());
ERR_FAIL_INDEX_V(p_surface, m->surfaces.size(), RS::SurfaceData());
RS::SurfaceData s = m->surfaces[p_surface];
return s;
}
virtual int mesh_get_surface_count(RID p_mesh) const override {
DummyMesh *m = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_NULL_V(m, 0);
return m->surfaces.size();
}
virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override {}
virtual AABB mesh_get_custom_aabb(RID p_mesh) const override { return AABB(); }
virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override { return AABB(); }
virtual void mesh_set_path(RID p_mesh, const String &p_path) override {}
virtual String mesh_get_path(RID p_mesh) const override { return String(); }
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override {}
virtual void mesh_clear(RID p_mesh) override;
/* MESH INSTANCE */
virtual RID mesh_instance_create(RID p_base) override { return RID(); }
virtual void mesh_instance_free(RID p_rid) override {}
virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override {}
virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override {}
virtual void mesh_instance_check_for_update(RID p_mesh_instance) override {}
virtual void mesh_instance_set_canvas_item_transform(RID p_mesh_instance, const Transform2D &p_transform) override {}
virtual void update_mesh_instances() override {}
/* MULTIMESH API */
bool owns_multimesh(RID p_rid) { return multimesh_owner.owns(p_rid); }
virtual RID multimesh_allocate() override;
virtual void multimesh_initialize(RID p_rid) override;
virtual void multimesh_free(RID p_rid) override;
virtual 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 {}
virtual int multimesh_get_instance_count(RID p_multimesh) const override { return 0; }
virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override {}
virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override {}
virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override {}
virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override {}
virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override {}
virtual void multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) override {}
virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const override { return AABB(); }
virtual RID multimesh_get_mesh(RID p_multimesh) const override { return RID(); }
virtual AABB multimesh_get_aabb(RID p_multimesh) const override { return AABB(); }
virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override { return Transform3D(); }
virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override { return Transform2D(); }
virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override { return Color(); }
virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override { return Color(); }
virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const override;
virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override {}
virtual int multimesh_get_visible_instances(RID p_multimesh) const override { return 0; }
/* SKELETON API */
virtual RID skeleton_allocate() override { return RID(); }
virtual void skeleton_initialize(RID p_rid) override {}
virtual void skeleton_free(RID p_rid) override {}
virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override {}
virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override {}
virtual int skeleton_get_bone_count(RID p_skeleton) const override { return 0; }
virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) override {}
virtual Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override { return Transform3D(); }
virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) override {}
virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const override { return Transform2D(); }
virtual void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) override {}
/* OCCLUDER */
void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) {}
};
} // namespace RendererDummy
#endif // MESH_STORAGE_DUMMY_H

View file

@ -0,0 +1,126 @@
/**************************************************************************/
/* particles_storage.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 PARTICLES_STORAGE_DUMMY_H
#define PARTICLES_STORAGE_DUMMY_H
#include "servers/rendering/storage/particles_storage.h"
namespace RendererDummy {
class ParticlesStorage : public RendererParticlesStorage {
public:
/* PARTICLES */
virtual RID particles_allocate() override { return RID(); }
virtual void particles_initialize(RID p_rid) override {}
virtual void particles_free(RID p_rid) override {}
virtual void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override {}
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) override {}
virtual void particles_set_emitting(RID p_particles, bool p_emitting) override {}
virtual void particles_set_amount(RID p_particles, int p_amount) override {}
virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) override {}
virtual void particles_set_lifetime(RID p_particles, double p_lifetime) override {}
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) override {}
virtual void particles_set_pre_process_time(RID p_particles, double p_time) override {}
virtual void particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) override {}
virtual void particles_set_randomness_ratio(RID p_particles, real_t p_ratio) override {}
virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) override {}
virtual void particles_set_speed_scale(RID p_particles, double p_scale) override {}
virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) override {}
virtual void particles_set_process_material(RID p_particles, RID p_material) override {}
virtual RID particles_get_process_material(RID p_particles) const override { return RID(); }
virtual void particles_set_fixed_fps(RID p_particles, int p_fps) override {}
virtual void particles_set_interpolate(RID p_particles, bool p_enable) override {}
virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) override {}
virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) override {}
virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) override {}
virtual void particles_set_collision_base_size(RID p_particles, real_t p_size) override {}
virtual void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) override {}
virtual void particles_set_trails(RID p_particles, bool p_enable, double p_length) override {}
virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) override {}
virtual void particles_restart(RID p_particles) override {}
virtual void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) override {}
virtual void particles_set_draw_passes(RID p_particles, int p_count) override {}
virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) override {}
virtual void particles_request_process(RID p_particles) override {}
virtual AABB particles_get_current_aabb(RID p_particles) override { return AABB(); }
virtual AABB particles_get_aabb(RID p_particles) const override { return AABB(); }
virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override {}
virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) override {}
virtual void particles_set_interp_to_end(RID p_particles, float p_interp) override {}
virtual bool particles_get_emitting(RID p_particles) override { return false; }
virtual int particles_get_draw_passes(RID p_particles) const override { return 0; }
virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const override { return RID(); }
virtual void particles_add_collision(RID p_particles, RID p_instance) override {}
virtual void particles_remove_collision(RID p_particles, RID p_instance) override {}
virtual void update_particles() override {}
/* PARTICLES COLLISION */
virtual RID particles_collision_allocate() override { return RID(); }
virtual void particles_collision_initialize(RID p_rid) override {}
virtual void particles_collision_free(RID p_rid) override {}
virtual void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) override {}
virtual void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) override {}
virtual void particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) override {}
virtual void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) override {}
virtual void particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) override {}
virtual void particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) override {}
virtual void particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) override {}
virtual void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) override {}
virtual void particles_collision_height_field_update(RID p_particles_collision) override {}
virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) override {}
virtual AABB particles_collision_get_aabb(RID p_particles_collision) const override { return AABB(); }
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override { return false; }
virtual RID particles_collision_instance_create(RID p_collision) override { return RID(); }
virtual void particles_collision_instance_free(RID p_rid) override {}
virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) override {}
virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override {}
virtual bool particles_is_inactive(RID p_particles) const override { return false; }
};
} // namespace RendererDummy
#endif // PARTICLES_STORAGE_DUMMY_H

View file

@ -0,0 +1,43 @@
/**************************************************************************/
/* texture_storage.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "texture_storage.h"
using namespace RendererDummy;
TextureStorage *TextureStorage::singleton = nullptr;
TextureStorage::TextureStorage() {
singleton = this;
}
TextureStorage::~TextureStorage() {
singleton = nullptr;
}

View file

@ -0,0 +1,211 @@
/**************************************************************************/
/* texture_storage.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 TEXTURE_STORAGE_DUMMY_H
#define TEXTURE_STORAGE_DUMMY_H
#include "servers/rendering/rendering_server_globals.h"
#include "servers/rendering/storage/texture_storage.h"
namespace RendererDummy {
class TextureStorage : public RendererTextureStorage {
private:
static TextureStorage *singleton;
struct DummyTexture {
Ref<Image> image;
};
mutable RID_PtrOwner<DummyTexture> texture_owner;
public:
static TextureStorage *get_singleton() { return singleton; }
TextureStorage();
~TextureStorage();
virtual bool can_create_resources_async() const override { return false; }
/* Canvas Texture API */
virtual RID canvas_texture_allocate() override { return RID(); };
virtual void canvas_texture_initialize(RID p_rid) override{};
virtual void canvas_texture_free(RID p_rid) override{};
virtual void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) override{};
virtual void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) override{};
virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override{};
virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override{};
/* Texture API */
bool owns_texture(RID p_rid) { return texture_owner.owns(p_rid); };
virtual RID texture_allocate() override {
DummyTexture *texture = memnew(DummyTexture);
ERR_FAIL_NULL_V(texture, RID());
return texture_owner.make_rid(texture);
};
virtual void texture_free(RID p_rid) override {
// delete the texture
DummyTexture *texture = texture_owner.get_or_null(p_rid);
ERR_FAIL_NULL(texture);
texture_owner.free(p_rid);
memdelete(texture);
};
virtual void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) override {
DummyTexture *t = texture_owner.get_or_null(p_texture);
ERR_FAIL_NULL(t);
t->image = p_image->duplicate();
};
virtual void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override{};
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) override{};
virtual void texture_proxy_initialize(RID p_texture, RID p_base) override{}; //all slices, then all the mipmaps, must be coherent
virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override{};
virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override{};
virtual void texture_proxy_update(RID p_proxy, RID p_base) override{};
//these two APIs can be used together or in combination with the others.
virtual void texture_2d_placeholder_initialize(RID p_texture) override{};
virtual void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) override{};
virtual void texture_3d_placeholder_initialize(RID p_texture) override{};
virtual Ref<Image> texture_2d_get(RID p_texture) const override {
DummyTexture *t = texture_owner.get_or_null(p_texture);
ERR_FAIL_NULL_V(t, Ref<Image>());
return t->image;
};
virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const override { return Ref<Image>(); };
virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const override { return Vector<Ref<Image>>(); };
virtual void texture_replace(RID p_texture, RID p_by_texture) override { texture_free(p_by_texture); };
virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) override{};
virtual void texture_set_path(RID p_texture, const String &p_path) override{};
virtual String texture_get_path(RID p_texture) const override { return String(); };
virtual Image::Format texture_get_format(RID p_texture) const override { return Image::FORMAT_MAX; }
virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override{};
virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override{};
virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) override{};
virtual void texture_debug_usage(List<RS::TextureInfo> *r_info) override{};
virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) override{};
virtual Size2 texture_size_with_proxy(RID p_proxy) override { return Size2(); };
virtual void texture_rd_initialize(RID p_texture, const RID &p_rd_texture, const RS::TextureLayeredType p_layer_type = RS::TEXTURE_LAYERED_2D_ARRAY) override{};
virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const override { return RID(); };
virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const override { return 0; };
/* DECAL API */
virtual RID decal_allocate() override { return RID(); }
virtual void decal_initialize(RID p_rid) override {}
virtual void decal_free(RID p_rid) override{};
virtual void decal_set_size(RID p_decal, const Vector3 &p_size) override {}
virtual void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) override {}
virtual void decal_set_emission_energy(RID p_decal, float p_energy) override {}
virtual void decal_set_albedo_mix(RID p_decal, float p_mix) override {}
virtual void decal_set_modulate(RID p_decal, const Color &p_modulate) override {}
virtual void decal_set_cull_mask(RID p_decal, uint32_t p_layers) override {}
virtual void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) override {}
virtual void decal_set_fade(RID p_decal, float p_above, float p_below) override {}
virtual void decal_set_normal_fade(RID p_decal, float p_fade) override {}
virtual AABB decal_get_aabb(RID p_decal) const override { return AABB(); }
virtual uint32_t decal_get_cull_mask(RID p_decal) const override { return 0; }
virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
/* DECAL INSTANCE */
virtual RID decal_instance_create(RID p_decal) override { return RID(); }
virtual void decal_instance_free(RID p_decal_instance) override {}
virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {}
virtual void decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) override {}
/* RENDER TARGET */
virtual RID render_target_create() override { return RID(); }
virtual void render_target_free(RID p_rid) override {}
virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) override {}
virtual Point2i render_target_get_position(RID p_render_target) const override { return Point2i(); }
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override {}
virtual Size2i render_target_get_size(RID p_render_target) const override { return Size2i(); }
virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override {}
virtual bool render_target_get_transparent(RID p_render_target) const override { return false; }
virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override {}
virtual bool render_target_get_direct_to_screen(RID p_render_target) const override { return false; }
virtual bool render_target_was_used(RID p_render_target) const override { return false; }
virtual void render_target_set_as_unused(RID p_render_target) override {}
virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override {}
virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const override { return RS::VIEWPORT_MSAA_DISABLED; }
virtual void render_target_set_msaa_needs_resolve(RID p_render_target, bool p_needs_resolve) override {}
virtual bool render_target_get_msaa_needs_resolve(RID p_render_target) const override { return false; }
virtual void render_target_do_msaa_resolve(RID p_render_target) override {}
virtual void render_target_set_use_hdr(RID p_render_target, bool p_use_hdr_2d) override {}
virtual bool render_target_is_using_hdr(RID p_render_target) const override { return false; }
virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) override {}
virtual bool render_target_is_clear_requested(RID p_render_target) override { return false; }
virtual Color render_target_get_clear_request_color(RID p_render_target) override { return Color(); }
virtual void render_target_disable_clear_request(RID p_render_target) override {}
virtual void render_target_do_clear_request(RID p_render_target) override {}
virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override {}
virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const override { return Rect2i(); }
virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override {}
virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override {}
virtual RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const override { return RS::VIEWPORT_VRS_DISABLED; }
virtual void render_target_set_vrs_update_mode(RID p_render_target, RS::ViewportVRSUpdateMode p_mode) override {}
virtual RS::ViewportVRSUpdateMode render_target_get_vrs_update_mode(RID p_render_target) const override { return RS::VIEWPORT_VRS_UPDATE_DISABLED; }
virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override {}
virtual RID render_target_get_vrs_texture(RID p_render_target) const override { return RID(); }
virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) override {}
virtual RID render_target_get_override_color(RID p_render_target) const override { return RID(); }
virtual RID render_target_get_override_depth(RID p_render_target) const override { return RID(); }
virtual RID render_target_get_override_velocity(RID p_render_target) const override { return RID(); }
virtual RID render_target_get_texture(RID p_render_target) override { return RID(); }
};
} // namespace RendererDummy
#endif // TEXTURE_STORAGE_DUMMY_H

View file

@ -0,0 +1,43 @@
/**************************************************************************/
/* utilities.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "utilities.h"
using namespace RendererDummy;
Utilities *Utilities::singleton = nullptr;
Utilities::Utilities() {
singleton = this;
}
Utilities::~Utilities() {
singleton = nullptr;
}

View file

@ -0,0 +1,132 @@
/**************************************************************************/
/* utilities.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 UTILITIES_DUMMY_H
#define UTILITIES_DUMMY_H
#include "light_storage.h"
#include "material_storage.h"
#include "mesh_storage.h"
#include "servers/rendering/storage/utilities.h"
#include "texture_storage.h"
namespace RendererDummy {
class Utilities : public RendererUtilities {
private:
static Utilities *singleton;
public:
static Utilities *get_singleton() { return singleton; }
Utilities();
~Utilities();
/* INSTANCES */
virtual RS::InstanceType get_base_type(RID p_rid) const override {
if (RendererDummy::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
return RS::INSTANCE_MESH;
} else if (RendererDummy::MeshStorage::get_singleton()->owns_multimesh(p_rid)) {
return RS::INSTANCE_MULTIMESH;
} else if (RendererDummy::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
return RS::INSTANCE_LIGHTMAP;
}
return RS::INSTANCE_NONE;
}
virtual bool free(RID p_rid) override {
if (RendererDummy::LightStorage::get_singleton()->free(p_rid)) {
return true;
} else if (RendererDummy::TextureStorage::get_singleton()->owns_texture(p_rid)) {
RendererDummy::TextureStorage::get_singleton()->texture_free(p_rid);
return true;
} else if (RendererDummy::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
RendererDummy::MeshStorage::get_singleton()->mesh_free(p_rid);
return true;
} else if (RendererDummy::MeshStorage::get_singleton()->owns_multimesh(p_rid)) {
RendererDummy::MeshStorage::get_singleton()->multimesh_free(p_rid);
return true;
} else if (RendererDummy::MaterialStorage::get_singleton()->owns_shader(p_rid)) {
RendererDummy::MaterialStorage::get_singleton()->shader_free(p_rid);
return true;
}
return false;
}
/* DEPENDENCIES */
virtual void base_update_dependency(RID p_base, DependencyTracker *p_instance) override {}
/* VISIBILITY NOTIFIER */
virtual RID visibility_notifier_allocate() override { return RID(); }
virtual void visibility_notifier_initialize(RID p_notifier) override {}
virtual void visibility_notifier_free(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 {}
/* TIMING */
virtual void capture_timestamps_begin() override {}
virtual void capture_timestamp(const String &p_name) override {}
virtual uint32_t get_captured_timestamps_count() const override { return 0; }
virtual uint64_t get_captured_timestamps_frame() const override { return 0; }
virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const override { return 0; }
virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const override { return 0; }
virtual String get_captured_timestamp_name(uint32_t p_index) const override { return String(); }
/* MISC */
virtual void update_dirty_resources() override {}
virtual void set_debug_generate_wireframes(bool p_generate) override {}
virtual bool has_os_feature(const String &p_feature) const override {
return p_feature == "rgtc" || p_feature == "bptc" || p_feature == "s3tc" || p_feature == "etc2";
}
virtual void update_memory_info() override {}
virtual uint64_t get_rendering_info(RS::RenderingInfo p_info) override { return 0; }
virtual String get_video_adapter_name() const override { return String(); }
virtual String get_video_adapter_vendor() const override { return String(); }
virtual RenderingDevice::DeviceType get_video_adapter_type() const override { return RenderingDevice::DeviceType::DEVICE_TYPE_OTHER; }
virtual String get_video_adapter_api_version() const override { return String(); }
virtual Size2i get_maximum_viewport_size() const override { return Size2i(); };
};
} // namespace RendererDummy
#endif // UTILITIES_DUMMY_H

View file

@ -0,0 +1,53 @@
/**************************************************************************/
/* renderer_fog.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 RENDERER_FOG_H
#define RENDERER_FOG_H
#include "servers/rendering_server.h"
class RendererFog {
public:
virtual ~RendererFog() {}
/* FOG VOLUMES */
virtual RID fog_volume_allocate() = 0;
virtual void fog_volume_initialize(RID p_rid) = 0;
virtual void fog_volume_free(RID p_rid) = 0;
virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) = 0;
virtual void fog_volume_set_size(RID p_fog_volume, const Vector3 &p_size) = 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;
};
#endif // RENDERER_FOG_H

View file

@ -0,0 +1,86 @@
/**************************************************************************/
/* renderer_gi.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 RENDERER_GI_H
#define RENDERER_GI_H
#include "servers/rendering_server.h"
class RendererGI {
public:
virtual ~RendererGI() {}
/* VOXEL GI API */
virtual RID voxel_gi_allocate() = 0;
virtual void voxel_gi_free(RID p_rid) = 0;
virtual void voxel_gi_initialize(RID p_rid) = 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 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> 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 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 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 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 voxel_gi_set_baked_exposure_normalization(RID p_voxel_gi, float p_baked_exposure) = 0;
virtual float voxel_gi_get_baked_exposure_normalization(RID p_voxel_gi) 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 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 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 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 uint32_t voxel_gi_get_version(RID p_probe) const = 0;
virtual void sdfgi_reset() = 0;
};
#endif // RENDERER_GI_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,381 @@
/**************************************************************************/
/* renderer_canvas_cull.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 RENDERER_CANVAS_CULL_H
#define RENDERER_CANVAS_CULL_H
#include "core/templates/paged_allocator.h"
#include "renderer_compositor.h"
#include "renderer_viewport.h"
class RendererCanvasCull {
public:
struct Item : public RendererCanvasRender::Item {
RID parent; // canvas it belongs to
List<Item *>::Element *E;
int z_index;
bool z_relative;
bool sort_y;
Color modulate;
Color self_modulate;
bool use_parent_material;
int index;
bool children_order_dirty;
int ysort_children_count;
Color ysort_modulate;
Transform2D ysort_xform;
Vector2 ysort_pos;
int ysort_index;
int ysort_parent_abs_z_index; // Absolute Z index of parent. Only populated and used when y-sorting.
uint32_t visibility_layer = 0xffffffff;
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;
z_index = 0;
modulate = Color(1, 1, 1, 1);
self_modulate = Color(1, 1, 1, 1);
sort_y = false;
use_parent_material = false;
z_relative = true;
index = 0;
ysort_children_count = -1;
ysort_xform = Transform2D();
ysort_pos = Vector2();
ysort_index = 0;
ysort_parent_abs_z_index = 0;
}
};
struct ItemIndexSort {
_FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const {
return p_left->index < p_right->index;
}
};
struct ItemPtrSort {
_FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const {
if (Math::is_equal_approx(p_left->ysort_pos.y, p_right->ysort_pos.y)) {
return p_left->ysort_index < p_right->ysort_index;
}
return p_left->ysort_pos.y < p_right->ysort_pos.y;
}
};
struct LightOccluderPolygon {
bool active;
Rect2 aabb;
RS::CanvasOccluderPolygonCullMode cull_mode;
RID occluder;
HashSet<RendererCanvasRender::LightOccluderInstance *> owners;
LightOccluderPolygon() {
active = false;
cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
}
};
RID_Owner<LightOccluderPolygon, true> canvas_light_occluder_polygon_owner;
RID_Owner<RendererCanvasRender::LightOccluderInstance, true> canvas_light_occluder_owner;
struct Canvas : public RendererViewport::CanvasBase {
HashSet<RID> viewports;
struct ChildItem {
Point2 mirror;
Item *item = nullptr;
bool operator<(const ChildItem &p_item) const {
return item->index < p_item.item->index;
}
};
HashSet<RendererCanvasRender::Light *> lights;
HashSet<RendererCanvasRender::Light *> directional_lights;
HashSet<RendererCanvasRender::LightOccluderInstance *> occluders;
bool children_order_dirty;
Vector<ChildItem> child_items;
Color modulate;
RID parent;
float parent_scale;
int find_item(Item *p_item) {
for (int i = 0; i < child_items.size(); i++) {
if (child_items[i].item == p_item) {
return i;
}
}
return -1;
}
void erase_item(Item *p_item) {
int idx = find_item(p_item);
if (idx >= 0) {
child_items.remove_at(idx);
}
}
Canvas() {
modulate = Color(1, 1, 1, 1);
children_order_dirty = true;
parent_scale = 1.0;
}
};
mutable RID_Owner<Canvas, true> canvas_owner;
RID_Owner<Item, true> canvas_item_owner;
RID_Owner<RendererCanvasRender::Light, true> canvas_light_owner;
template <typename T>
void _free_rids(T &p_owner, const char *p_type);
bool disable_scale;
bool sdf_used = false;
bool snapping_2d_transforms_to_pixel = false;
bool debug_redraw = false;
double debug_redraw_time = 0;
Color debug_redraw_color;
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 **r_z_list, RendererCanvasRender::Item **r_z_last_list, const Transform2D &p_transform, const Rect2 &p_clip_rect, Rect2 p_global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool p_use_canvas_group, RendererCanvasRender::Item *r_canvas_group_from);
private:
void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, 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, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info = nullptr);
void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_parent_xform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool p_allow_y_sort, uint32_t p_canvas_cull_mask, const Point2 &p_repeat_size, int p_repeat_times);
static constexpr int z_range = RS::CANVAS_ITEM_Z_MAX - RS::CANVAS_ITEM_Z_MIN + 1;
RendererCanvasRender::Item **z_list;
RendererCanvasRender::Item **z_last_list;
public:
void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, const Rect2 &p_clip_rect, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info = nullptr);
bool was_sdf_used();
RID canvas_allocate();
void canvas_initialize(RID p_rid);
void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring);
void canvas_set_item_repeat(RID p_item, const Point2 &p_repeat_size, int p_repeat_times);
void canvas_set_modulate(RID p_canvas, const Color &p_color);
void canvas_set_parent(RID p_canvas, RID p_parent, float p_scale);
void canvas_set_disable_scale(bool p_disable);
RID canvas_item_allocate();
void canvas_item_initialize(RID p_rid);
void canvas_item_set_parent(RID p_item, RID p_parent);
void canvas_item_set_visible(RID p_item, bool p_visible);
void canvas_item_set_light_mask(RID p_item, int p_mask);
void canvas_item_set_visibility_layer(RID p_item, uint32_t p_layer);
uint32_t canvas_item_get_visibility_layer(RID p_item);
void canvas_item_set_transform(RID p_item, const Transform2D &p_transform);
void canvas_item_set_clip(RID p_item, bool p_clip);
void canvas_item_set_distance_field_mode(RID p_item, bool p_enable);
void canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect = Rect2());
void canvas_item_set_modulate(RID p_item, const Color &p_color);
void canvas_item_set_self_modulate(RID p_item, const Color &p_color);
void canvas_item_set_draw_behind_parent(RID p_item, bool p_enable);
void canvas_item_set_update_when_visible(RID p_item, bool p_update);
void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = -1.0, bool p_antialiased = false);
void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0, bool p_antialiased = false);
void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0, bool p_antialiased = false);
void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color, bool p_antialiased);
void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color, bool p_antialiased);
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, float p_scale = 1.0);
void canvas_item_add_lcd_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));
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);
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());
void 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 = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1);
void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID());
void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID());
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);
void canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect);
void canvas_item_attach_skeleton(RID p_item, RID p_skeleton);
void canvas_item_clear(RID p_item);
void canvas_item_set_draw_index(RID p_item, int p_index);
void canvas_item_set_material(RID p_item, RID p_material);
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);
void canvas_item_set_debug_redraw(bool p_enabled);
bool canvas_item_get_debug_redraw() const;
void canvas_item_set_interpolated(RID p_item, bool p_interpolated);
void canvas_item_reset_physics_interpolation(RID p_item);
void canvas_item_transform_physics_interpolation(RID p_item, const Transform2D &p_transform);
RID canvas_light_allocate();
void canvas_light_initialize(RID p_rid);
void canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode);
void canvas_light_attach_to_canvas(RID p_light, RID p_canvas);
void canvas_light_set_enabled(RID p_light, bool p_enabled);
void canvas_light_set_texture_scale(RID p_light, float p_scale);
void canvas_light_set_transform(RID p_light, const Transform2D &p_transform);
void canvas_light_set_texture(RID p_light, RID p_texture);
void canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset);
void canvas_light_set_color(RID p_light, const Color &p_color);
void canvas_light_set_height(RID p_light, float p_height);
void canvas_light_set_energy(RID p_light, float p_energy);
void canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z);
void canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer);
void canvas_light_set_item_cull_mask(RID p_light, int p_mask);
void canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask);
void canvas_light_set_directional_distance(RID p_light, float p_distance);
void canvas_light_set_blend_mode(RID p_light, RS::CanvasLightBlendMode p_mode);
void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled);
void canvas_light_set_shadow_filter(RID p_light, RS::CanvasLightShadowFilter p_filter);
void canvas_light_set_shadow_color(RID p_light, const Color &p_color);
void canvas_light_set_shadow_smooth(RID p_light, float p_smooth);
void canvas_light_set_interpolated(RID p_light, bool p_interpolated);
void canvas_light_reset_physics_interpolation(RID p_light);
void canvas_light_transform_physics_interpolation(RID p_light, const Transform2D &p_transform);
RID canvas_light_occluder_allocate();
void canvas_light_occluder_initialize(RID p_rid);
void canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas);
void canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled);
void canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon);
void canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable);
void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform);
void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask);
void canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated);
void canvas_light_occluder_reset_physics_interpolation(RID p_occluder);
void canvas_light_occluder_transform_physics_interpolation(RID p_occluder, const Transform2D &p_transform);
RID canvas_occluder_polygon_allocate();
void canvas_occluder_polygon_initialize(RID p_rid);
void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed);
void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode);
void canvas_set_shadow_texture_size(int p_size);
RID canvas_texture_allocate();
void canvas_texture_initialize(RID p_rid);
void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture);
void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess);
void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter);
void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat);
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();
Rect2 _debug_canvas_item_get_rect(RID p_item);
bool free(RID p_rid);
void finalize();
/* INTERPOLATION */
void tick();
void update_interpolation_tick(bool p_process = true);
void set_physics_interpolation_enabled(bool p_enabled) { _interpolation_data.interpolation_enabled = p_enabled; }
struct InterpolationData {
void notify_free_canvas_item(RID p_rid, RendererCanvasCull::Item &r_canvas_item);
void notify_free_canvas_light(RID p_rid, RendererCanvasRender::Light &r_canvas_light);
void notify_free_canvas_light_occluder(RID p_rid, RendererCanvasRender::LightOccluderInstance &r_canvas_light_occluder);
LocalVector<RID> canvas_item_transform_update_lists[2];
LocalVector<RID> *canvas_item_transform_update_list_curr = &canvas_item_transform_update_lists[0];
LocalVector<RID> *canvas_item_transform_update_list_prev = &canvas_item_transform_update_lists[1];
LocalVector<RID> canvas_light_transform_update_lists[2];
LocalVector<RID> *canvas_light_transform_update_list_curr = &canvas_light_transform_update_lists[0];
LocalVector<RID> *canvas_light_transform_update_list_prev = &canvas_light_transform_update_lists[1];
LocalVector<RID> canvas_light_occluder_transform_update_lists[2];
LocalVector<RID> *canvas_light_occluder_transform_update_list_curr = &canvas_light_occluder_transform_update_lists[0];
LocalVector<RID> *canvas_light_occluder_transform_update_list_prev = &canvas_light_occluder_transform_update_lists[1];
bool interpolation_enabled = false;
} _interpolation_data;
RendererCanvasCull();
~RendererCanvasCull();
};
#endif // RENDERER_CANVAS_CULL_H

View file

@ -0,0 +1,138 @@
/**************************************************************************/
/* renderer_canvas_render.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "renderer_canvas_render.h"
#include "servers/rendering/rendering_server_globals.h"
RendererCanvasRender *RendererCanvasRender::singleton = nullptr;
const Rect2 &RendererCanvasRender::Item::get_rect() const {
if (custom_rect || (!rect_dirty && !update_when_visible && skeleton == RID())) {
return rect;
}
//must update rect
if (commands == nullptr) {
rect = Rect2();
rect_dirty = false;
return rect;
}
Transform2D xf;
bool found_xform = false;
bool first = true;
const Item::Command *c = commands;
while (c) {
Rect2 r;
switch (c->type) {
case Item::Command::TYPE_RECT: {
const Item::CommandRect *crect = static_cast<const Item::CommandRect *>(c);
r = crect->rect;
} break;
case Item::Command::TYPE_NINEPATCH: {
const Item::CommandNinePatch *style = static_cast<const Item::CommandNinePatch *>(c);
r = style->rect;
} break;
case Item::Command::TYPE_POLYGON: {
const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c);
r = polygon->polygon.rect_cache;
} break;
case Item::Command::TYPE_PRIMITIVE: {
const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
for (uint32_t j = 0; j < primitive->point_count; j++) {
if (j == 0) {
r.position = primitive->points[0];
} else {
r.expand_to(primitive->points[j]);
}
}
} break;
case Item::Command::TYPE_MESH: {
const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c);
AABB aabb = RSG::mesh_storage->mesh_get_aabb(mesh->mesh, skeleton);
r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
} break;
case Item::Command::TYPE_MULTIMESH: {
const Item::CommandMultiMesh *multimesh = static_cast<const Item::CommandMultiMesh *>(c);
AABB aabb = RSG::mesh_storage->multimesh_get_aabb(multimesh->multimesh);
r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
} break;
case Item::Command::TYPE_PARTICLES: {
const Item::CommandParticles *particles_cmd = static_cast<const Item::CommandParticles *>(c);
if (particles_cmd->particles.is_valid()) {
AABB aabb = RSG::particles_storage->particles_get_aabb(particles_cmd->particles);
r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
}
} break;
case Item::Command::TYPE_TRANSFORM: {
const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
xf = transform->xform;
found_xform = true;
[[fallthrough]];
}
default: {
c = c->next;
continue;
}
}
if (found_xform) {
r = xf.xform(r);
}
if (first) {
rect = r;
first = false;
} else {
rect = rect.merge(r);
}
c = c->next;
}
rect_dirty = false;
return rect;
}
RendererCanvasRender::Item::CommandMesh::~CommandMesh() {
if (mesh_instance.is_valid()) {
RSG::mesh_storage->mesh_instance_free(mesh_instance);
}
}

View file

@ -0,0 +1,557 @@
/**************************************************************************/
/* renderer_canvas_render.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 RENDERER_CANVAS_RENDER_H
#define RENDERER_CANVAS_RENDER_H
#include "servers/rendering/rendering_method.h"
#include "servers/rendering_server.h"
class RendererCanvasRender {
public:
static RendererCanvasRender *singleton;
enum CanvasRectFlags {
CANVAS_RECT_REGION = 1,
CANVAS_RECT_TILE = 2,
CANVAS_RECT_FLIP_H = 4,
CANVAS_RECT_FLIP_V = 8,
CANVAS_RECT_TRANSPOSE = 16,
CANVAS_RECT_CLIP_UV = 32,
CANVAS_RECT_IS_GROUP = 64,
CANVAS_RECT_MSDF = 128,
CANVAS_RECT_LCD = 256,
};
struct Light {
bool enabled : 1;
bool on_interpolate_transform_list : 1;
bool interpolated : 1;
Color color;
Transform2D xform_curr;
Transform2D xform_prev;
float height;
float energy;
float scale;
int z_min;
int z_max;
int layer_min;
int layer_max;
int item_mask;
int item_shadow_mask;
float directional_distance;
RS::CanvasLightMode mode;
RS::CanvasLightBlendMode blend_mode;
RID texture;
Vector2 texture_offset;
RID canvas;
bool use_shadow;
int shadow_buffer_size;
RS::CanvasLightShadowFilter shadow_filter;
Color shadow_color;
float shadow_smooth;
//void *texture_cache; // implementation dependent
Rect2 rect_cache;
Transform2D xform_cache;
float radius_cache; //used for shadow far plane
//Projection shadow_matrix_cache;
Transform2D light_shader_xform;
//Vector2 light_shader_pos;
Light *shadows_next_ptr = nullptr;
Light *filter_next_ptr = nullptr;
Light *next_ptr = nullptr;
Light *directional_next_ptr = nullptr;
RID light_internal;
uint64_t version;
int32_t render_index_cache;
Light() {
version = 0;
enabled = true;
on_interpolate_transform_list = false;
interpolated = true;
color = Color(1, 1, 1);
shadow_color = Color(0, 0, 0, 0);
height = 0;
z_min = -1024;
z_max = 1024;
layer_min = 0;
layer_max = 0;
item_mask = 1;
scale = 1.0;
energy = 1.0;
item_shadow_mask = 1;
mode = RS::CANVAS_LIGHT_MODE_POINT;
blend_mode = RS::CANVAS_LIGHT_BLEND_MODE_ADD;
// texture_cache = nullptr;
next_ptr = nullptr;
directional_next_ptr = nullptr;
filter_next_ptr = nullptr;
use_shadow = false;
shadow_buffer_size = 2048;
shadow_filter = RS::CANVAS_LIGHT_FILTER_NONE;
shadow_smooth = 0.0;
render_index_cache = -1;
directional_distance = 10000.0;
}
};
//easier wrap to avoid mistakes
struct Item;
typedef uint64_t PolygonID;
virtual 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>()) = 0;
virtual void free_polygon(PolygonID p_polygon) = 0;
//also easier to wrap to avoid mistakes
struct Polygon {
PolygonID polygon_id;
Rect2 rect_cache;
_FORCE_INLINE_ void create(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>()) {
ERR_FAIL_COND(polygon_id != 0);
{
uint32_t pc = p_points.size();
const Vector2 *v2 = p_points.ptr();
rect_cache.position = *v2;
for (uint32_t i = 1; i < pc; i++) {
rect_cache.expand_to(v2[i]);
}
}
polygon_id = singleton->request_polygon(p_indices, p_points, p_colors, p_uvs, p_bones, p_weights);
}
_FORCE_INLINE_ Polygon() { polygon_id = 0; }
_FORCE_INLINE_ ~Polygon() {
if (polygon_id) {
singleton->free_polygon(polygon_id);
}
}
};
//item
struct Item {
//commands are allocated in blocks of 4k to improve performance
//and cache coherence.
//blocks always grow but never shrink.
struct CommandBlock {
enum {
MAX_SIZE = 4096
};
uint32_t usage;
uint8_t *memory = nullptr;
};
struct Command {
enum Type {
TYPE_RECT,
TYPE_NINEPATCH,
TYPE_POLYGON,
TYPE_PRIMITIVE,
TYPE_MESH,
TYPE_MULTIMESH,
TYPE_PARTICLES,
TYPE_TRANSFORM,
TYPE_CLIP_IGNORE,
TYPE_ANIMATION_SLICE,
};
Command *next = nullptr;
Type type;
virtual ~Command() {}
};
struct CommandRect : public Command {
Rect2 rect;
Color modulate;
Rect2 source;
uint16_t flags;
float outline;
float px_range;
RID texture;
CommandRect() {
flags = 0;
outline = 0;
px_range = 1;
type = TYPE_RECT;
}
};
struct CommandNinePatch : public Command {
Rect2 rect;
Rect2 source;
float margin[4];
bool draw_center;
Color color;
RS::NinePatchAxisMode axis_x;
RS::NinePatchAxisMode axis_y;
RID texture;
CommandNinePatch() {
draw_center = true;
type = TYPE_NINEPATCH;
}
};
struct CommandPolygon : public Command {
RS::PrimitiveType primitive;
Polygon polygon;
RID texture;
CommandPolygon() {
type = TYPE_POLYGON;
}
};
struct CommandPrimitive : public Command {
uint32_t point_count;
Vector2 points[4];
Vector2 uvs[4];
Color colors[4];
RID texture;
CommandPrimitive() {
type = TYPE_PRIMITIVE;
}
};
struct CommandMesh : public Command {
RID mesh;
Transform2D transform;
Color modulate;
RID mesh_instance;
RID texture;
CommandMesh() { type = TYPE_MESH; }
~CommandMesh();
};
struct CommandMultiMesh : public Command {
RID multimesh;
RID texture;
CommandMultiMesh() { type = TYPE_MULTIMESH; }
};
struct CommandParticles : public Command {
RID particles;
RID texture;
CommandParticles() { type = TYPE_PARTICLES; }
};
struct CommandTransform : public Command {
Transform2D xform;
CommandTransform() { type = TYPE_TRANSFORM; }
};
struct CommandClipIgnore : public Command {
bool ignore;
CommandClipIgnore() {
type = TYPE_CLIP_IGNORE;
ignore = false;
}
};
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 = nullptr;
void *udata = nullptr;
Rect2 rect;
};
// For interpolation we store the current local xform,
// and the previous xform from the previous tick.
Transform2D xform_curr;
Transform2D xform_prev;
bool clip : 1;
bool visible : 1;
bool behind : 1;
bool update_when_visible : 1;
bool on_interpolate_transform_list : 1;
bool interpolated : 1;
struct CanvasGroup {
RS::CanvasGroupMode mode;
bool fit_empty;
float fit_margin;
bool blur_mipmaps;
float clear_margin;
};
CanvasGroup *canvas_group = nullptr;
bool use_canvas_group = false;
int light_mask;
int z_final;
mutable bool custom_rect;
mutable bool rect_dirty;
mutable Rect2 rect;
RID material;
RID skeleton;
Item *next = nullptr;
struct CopyBackBuffer {
Rect2 rect;
Rect2 screen_rect;
bool full;
};
CopyBackBuffer *copy_back_buffer = nullptr;
Color final_modulate;
Transform2D final_transform;
Rect2 final_clip_rect;
Item *final_clip_owner = nullptr;
Item *material_owner = nullptr;
Item *canvas_group_owner = nullptr;
ViewportRender *vp_render = nullptr;
bool distance_field;
bool light_masked;
bool repeat_source;
Point2 repeat_size;
int repeat_times = 1;
Rect2 global_rect_cache;
const Rect2 &get_rect() const;
Command *commands = nullptr;
Command *last_command = nullptr;
Vector<CommandBlock> blocks;
uint32_t current_block;
#ifdef DEBUG_ENABLED
mutable double debug_redraw_time = 0;
#endif
template <typename T>
T *alloc_command() {
T *command = nullptr;
if (commands == nullptr) {
// As the most common use case of canvas items is to
// use only one command, the first is done with it's
// own allocation. The rest of them use blocks.
command = memnew(T);
command->next = nullptr;
commands = command;
last_command = command;
} else {
//Subsequent commands go into a block.
while (true) {
if (unlikely(current_block == (uint32_t)blocks.size())) {
// If we need more blocks, we allocate them
// (they won't be freed until this CanvasItem is
// deleted, though).
CommandBlock cb;
cb.memory = (uint8_t *)memalloc(CommandBlock::MAX_SIZE);
cb.usage = 0;
blocks.push_back(cb);
}
CommandBlock *c = &blocks.write[current_block];
size_t space_left = CommandBlock::MAX_SIZE - c->usage;
if (space_left < sizeof(T)) {
current_block++;
continue;
}
//allocate block and add to the linked list
void *memory = c->memory + c->usage;
command = memnew_placement(memory, T);
command->next = nullptr;
last_command->next = command;
last_command = command;
c->usage += sizeof(T);
break;
}
}
rect_dirty = true;
return command;
}
void clear() {
// The first one is always allocated on heap
// the rest go in the blocks
Command *c = commands;
while (c) {
Command *n = c->next;
if (c == commands) {
memdelete(commands);
commands = nullptr;
} else {
c->~Command();
}
c = n;
}
{
uint32_t cbc = MIN((current_block + 1), (uint32_t)blocks.size());
CommandBlock *blockptr = blocks.ptrw();
for (uint32_t i = 0; i < cbc; i++) {
blockptr[i].usage = 0;
}
}
last_command = nullptr;
commands = nullptr;
current_block = 0;
clip = false;
rect_dirty = true;
final_clip_owner = nullptr;
material_owner = nullptr;
light_masked = false;
}
RS::CanvasItemTextureFilter texture_filter;
RS::CanvasItemTextureRepeat texture_repeat;
Item() {
commands = nullptr;
last_command = nullptr;
current_block = 0;
light_mask = 1;
vp_render = nullptr;
next = nullptr;
final_clip_owner = nullptr;
canvas_group_owner = nullptr;
clip = false;
final_modulate = Color(1, 1, 1, 1);
visible = true;
rect_dirty = true;
custom_rect = false;
behind = false;
material_owner = nullptr;
copy_back_buffer = nullptr;
distance_field = false;
light_masked = false;
update_when_visible = false;
z_final = 0;
texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
repeat_source = false;
on_interpolate_transform_list = false;
interpolated = true;
}
virtual ~Item() {
clear();
for (int i = 0; i < blocks.size(); i++) {
memfree(blocks[i].memory);
}
if (copy_back_buffer) {
memdelete(copy_back_buffer);
}
}
};
virtual 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, RenderingMethod::RenderInfo *r_render_info = nullptr) = 0;
struct LightOccluderInstance {
bool enabled : 1;
bool on_interpolate_transform_list : 1;
bool interpolated : 1;
RID canvas;
RID polygon;
RID occluder;
Rect2 aabb_cache;
Transform2D xform_curr;
Transform2D xform_prev;
Transform2D xform_cache;
int light_mask;
bool sdf_collision;
RS::CanvasOccluderPolygonCullMode cull_cache;
LightOccluderInstance *next = nullptr;
LightOccluderInstance() {
enabled = true;
on_interpolate_transform_list = false;
interpolated = false;
sdf_collision = false;
next = nullptr;
light_mask = 1;
cull_cache = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
}
};
virtual RID light_create() = 0;
virtual void light_set_texture(RID p_rid, RID p_texture) = 0;
virtual void light_set_use_shadow(RID p_rid, bool p_enable) = 0;
virtual 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) = 0;
virtual 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) = 0;
virtual void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) = 0;
virtual RID occluder_polygon_create() = 0;
virtual void occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) = 0;
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 bool free(RID p_rid) = 0;
virtual void update() = 0;
virtual void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) = 0;
RendererCanvasRender() {
ERR_FAIL_COND_MSG(singleton != nullptr, "A RendererCanvasRender singleton already exists.");
singleton = this;
}
virtual ~RendererCanvasRender() {
singleton = nullptr;
}
};
#endif // RENDERER_CANVAS_RENDER_H

View file

@ -0,0 +1,64 @@
/**************************************************************************/
/* renderer_compositor.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "renderer_compositor.h"
#include "core/config/project_settings.h"
#include "servers/xr_server.h"
RendererCompositor *RendererCompositor::singleton = nullptr;
RendererCompositor *(*RendererCompositor::_create_func)() = nullptr;
bool RendererCompositor::low_end = false;
RendererCompositor *RendererCompositor::create() {
return _create_func();
}
bool RendererCompositor::is_xr_enabled() const {
return xr_enabled;
}
RendererCompositor::RendererCompositor() {
ERR_FAIL_COND_MSG(singleton != nullptr, "A RendererCompositor singleton already exists.");
singleton = this;
#ifndef _3D_DISABLED
if (XRServer::get_xr_mode() == XRServer::XRMODE_DEFAULT) {
xr_enabled = GLOBAL_GET("xr/shaders/enabled");
} else {
xr_enabled = XRServer::get_xr_mode() == XRServer::XRMODE_ON;
}
#endif // _3D_DISABLED
}
RendererCompositor::~RendererCompositor() {
singleton = nullptr;
}

View file

@ -0,0 +1,116 @@
/**************************************************************************/
/* renderer_compositor.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 RENDERER_COMPOSITOR_H
#define RENDERER_COMPOSITOR_H
#include "servers/rendering/environment/renderer_fog.h"
#include "servers/rendering/environment/renderer_gi.h"
#include "servers/rendering/renderer_canvas_render.h"
#include "servers/rendering/rendering_method.h"
#include "servers/rendering/storage/camera_attributes_storage.h"
#include "servers/rendering/storage/light_storage.h"
#include "servers/rendering/storage/material_storage.h"
#include "servers/rendering/storage/mesh_storage.h"
#include "servers/rendering/storage/particles_storage.h"
#include "servers/rendering/storage/texture_storage.h"
#include "servers/rendering/storage/utilities.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;
static RendererCompositor *singleton;
protected:
static RendererCompositor *(*_create_func)();
bool back_end = false;
static bool low_end;
public:
static RendererCompositor *create();
virtual RendererUtilities *get_utilities() = 0;
virtual RendererLightStorage *get_light_storage() = 0;
virtual RendererMaterialStorage *get_material_storage() = 0;
virtual RendererMeshStorage *get_mesh_storage() = 0;
virtual RendererParticlesStorage *get_particles_storage() = 0;
virtual RendererTextureStorage *get_texture_storage() = 0;
virtual RendererGI *get_gi() = 0;
virtual RendererFog *get_fog() = 0;
virtual RendererCanvasRender *get_canvas() = 0;
virtual RendererSceneRender *get_scene() = 0;
virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) = 0;
virtual void initialize() = 0;
virtual void begin_frame(double frame_step) = 0;
virtual void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0;
virtual void gl_end_frame(bool p_swap_buffers) = 0;
virtual void end_frame(bool p_swap_buffers) = 0;
virtual void finalize() = 0;
virtual uint64_t get_frame_number() const = 0;
virtual double get_frame_delta_time() const = 0;
virtual double get_total_time() const = 0;
static bool is_low_end() { return low_end; };
virtual bool is_xr_enabled() const;
static RendererCompositor *get_singleton() { return singleton; }
RendererCompositor();
virtual ~RendererCompositor();
};
#endif // RENDERER_COMPOSITOR_H

View file

@ -0,0 +1,143 @@
/**************************************************************************/
/* renderer_geometry_instance.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "servers/rendering/renderer_geometry_instance.h"
void RenderGeometryInstanceBase::set_skeleton(RID p_skeleton) {
data->skeleton = p_skeleton;
_mark_dirty();
data->dirty_dependencies = true;
}
void RenderGeometryInstanceBase::set_material_override(RID p_override) {
data->material_override = p_override;
_mark_dirty();
data->dirty_dependencies = true;
}
void RenderGeometryInstanceBase::set_material_overlay(RID p_overlay) {
data->material_overlay = p_overlay;
_mark_dirty();
data->dirty_dependencies = true;
}
void RenderGeometryInstanceBase::set_surface_materials(const Vector<RID> &p_materials) {
data->surface_materials = p_materials;
_mark_dirty();
data->dirty_dependencies = true;
}
void RenderGeometryInstanceBase::set_mesh_instance(RID p_mesh_instance) {
mesh_instance = p_mesh_instance;
_mark_dirty();
}
void RenderGeometryInstanceBase::set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
transform = p_transform;
mirror = p_transform.basis.determinant() < 0;
data->aabb = p_aabb;
transformed_aabb = p_transformed_aabb;
Vector3 model_scale_vec = p_transform.basis.get_scale_abs();
// handle non uniform scale here
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));
non_uniform_scale = max_scale >= 0.0 && (min_scale / max_scale) < 0.9;
lod_model_scale = max_scale;
}
void RenderGeometryInstanceBase::set_pivot_data(float p_sorting_offset, bool p_use_aabb_center) {
sorting_offset = p_sorting_offset;
use_aabb_center = p_use_aabb_center;
}
void RenderGeometryInstanceBase::set_lod_bias(float p_lod_bias) {
lod_bias = p_lod_bias;
}
void RenderGeometryInstanceBase::set_layer_mask(uint32_t p_layer_mask) {
layer_mask = p_layer_mask;
}
void RenderGeometryInstanceBase::set_fade_range(bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) {
fade_near = p_enable_near;
fade_near_begin = p_near_begin;
fade_near_end = p_near_end;
fade_far = p_enable_far;
fade_far_begin = p_far_begin;
fade_far_end = p_far_end;
}
void RenderGeometryInstanceBase::set_parent_fade_alpha(float p_alpha) {
parent_fade_alpha = p_alpha;
}
void RenderGeometryInstanceBase::set_transparency(float p_transparency) {
force_alpha = CLAMP(1.0 - p_transparency, 0, 1);
}
void RenderGeometryInstanceBase::set_use_baked_light(bool p_enable) {
data->use_baked_light = p_enable;
_mark_dirty();
}
void RenderGeometryInstanceBase::set_use_dynamic_gi(bool p_enable) {
data->use_dynamic_gi = p_enable;
_mark_dirty();
}
void RenderGeometryInstanceBase::set_instance_shader_uniforms_offset(int32_t p_offset) {
shader_uniforms_offset = p_offset;
_mark_dirty();
}
void RenderGeometryInstanceBase::set_cast_double_sided_shadows(bool p_enable) {
data->cast_double_sided_shadows = p_enable;
_mark_dirty();
}
Transform3D RenderGeometryInstanceBase::get_transform() {
return transform;
}
AABB RenderGeometryInstanceBase::get_aabb() {
return data->aabb;
}

View file

@ -0,0 +1,154 @@
/**************************************************************************/
/* renderer_geometry_instance.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 RENDERER_GEOMETRY_INSTANCE_H
#define RENDERER_GEOMETRY_INSTANCE_H
#include "core/math/rect2.h"
#include "core/math/transform_3d.h"
#include "core/math/vector3.h"
#include "core/templates/rid.h"
#include "storage/utilities.h"
// API definition for our RenderGeometryInstance class so we can expose this through GDExtension in the near future
class RenderGeometryInstance {
public:
virtual ~RenderGeometryInstance() {}
virtual void _mark_dirty() = 0;
virtual void set_skeleton(RID p_skeleton) = 0;
virtual void set_material_override(RID p_override) = 0;
virtual void set_material_overlay(RID p_overlay) = 0;
virtual void set_surface_materials(const Vector<RID> &p_materials) = 0;
virtual void set_mesh_instance(RID p_mesh_instance) = 0;
virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) = 0;
virtual void set_pivot_data(float p_sorting_offset, bool p_use_aabb_center) = 0;
virtual void set_lod_bias(float p_lod_bias) = 0;
virtual void set_layer_mask(uint32_t p_layer_mask) = 0;
virtual void set_fade_range(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 set_parent_fade_alpha(float p_alpha) = 0;
virtual void set_transparency(float p_transparency) = 0;
virtual void set_use_baked_light(bool p_enable) = 0;
virtual void set_use_dynamic_gi(bool p_enable) = 0;
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) = 0;
virtual void set_lightmap_capture(const Color *p_sh9) = 0;
virtual void set_instance_shader_uniforms_offset(int32_t p_offset) = 0;
virtual void set_cast_double_sided_shadows(bool p_enable) = 0;
virtual Transform3D get_transform() = 0;
virtual AABB get_aabb() = 0;
virtual void pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) = 0;
virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) = 0;
virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) = 0;
virtual void pair_voxel_gi_instances(const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) = 0;
virtual void set_softshadow_projector_pairing(bool p_softshadow, bool p_projector) = 0;
};
// Base implementation of RenderGeometryInstance shared by internal renderers.
class RenderGeometryInstanceBase : public RenderGeometryInstance {
public:
// setup
uint32_t base_flags = 0;
uint32_t flags_cache = 0;
// used during rendering
float depth = 0;
RID mesh_instance;
Transform3D transform;
bool mirror = false;
AABB transformed_aabb;
bool non_uniform_scale = false;
float lod_model_scale = 1.0;
float lod_bias = 0.0;
float sorting_offset = 0.0;
bool use_aabb_center = true;
uint32_t layer_mask = 1;
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 parent_fade_alpha = 1.0;
float force_alpha = 1.0;
int32_t shader_uniforms_offset = -1;
struct Data {
//data used less often goes into regular heap
RID base;
RS::InstanceType base_type;
RID skeleton;
Vector<RID> surface_materials;
RID material_override;
RID material_overlay;
AABB aabb;
bool use_baked_light = false;
bool use_dynamic_gi = false;
bool cast_double_sided_shadows = false;
bool dirty_dependencies = false;
DependencyTracker dependency_tracker;
};
Data *data = nullptr;
virtual void set_skeleton(RID p_skeleton) override;
virtual void set_material_override(RID p_override) override;
virtual void set_material_overlay(RID p_overlay) override;
virtual void set_surface_materials(const Vector<RID> &p_materials) override;
virtual void set_mesh_instance(RID p_mesh_instance) override;
virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override;
virtual void set_pivot_data(float p_sorting_offset, bool p_use_aabb_center) override;
virtual void set_lod_bias(float p_lod_bias) override;
virtual void set_layer_mask(uint32_t p_layer_mask) override;
virtual void set_fade_range(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 set_parent_fade_alpha(float p_alpha) override;
virtual void set_transparency(float p_transparency) override;
virtual void set_use_baked_light(bool p_enable) override;
virtual void set_use_dynamic_gi(bool p_enable) override;
virtual void set_instance_shader_uniforms_offset(int32_t p_offset) override;
virtual void set_cast_double_sided_shadows(bool p_enable) override;
virtual Transform3D get_transform() override;
virtual AABB get_aabb() override;
};
#endif // RENDERER_GEOMETRY_INSTANCE_H

View file

@ -0,0 +1,13 @@
#!/usr/bin/env python
Import("env")
env.add_source_files(env.servers_sources, "*.cpp")
SConscript("effects/SCsub")
SConscript("environment/SCsub")
SConscript("forward_clustered/SCsub")
SConscript("forward_mobile/SCsub")
SConscript("shaders/SCsub")
SConscript("spirv-reflect/SCsub")
SConscript("storage_rd/SCsub")

View file

@ -0,0 +1,573 @@
/**************************************************************************/
/* cluster_builder_rd.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "cluster_builder_rd.h"
#include "servers/rendering/rendering_device.h"
#include "servers/rendering/rendering_server_globals.h"
ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() {
RD::VertexFormatID vertex_format;
{
Vector<RD::VertexAttribute> attributes;
{
RD::VertexAttribute va;
va.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
va.stride = sizeof(float) * 3;
attributes.push_back(va);
}
vertex_format = RD::get_singleton()->vertex_format_create(attributes);
}
{
RD::FramebufferFormatID fb_format;
RD::PipelineColorBlendState blend_state;
String defines;
if (RD::get_singleton()->has_feature(RD::SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS)) {
fb_format = RD::get_singleton()->framebuffer_format_create_empty();
blend_state = RD::PipelineColorBlendState::create_disabled();
} else {
Vector<RD::AttachmentFormat> afs;
afs.push_back(RD::AttachmentFormat());
afs.write[0].usage_flags = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
fb_format = RD::get_singleton()->framebuffer_format_create(afs);
blend_state = RD::PipelineColorBlendState::create_blend();
defines = "\n#define USE_ATTACHMENT\n";
}
RD::PipelineRasterizationState rasterization_state;
rasterization_state.enable_depth_clamp = true;
Vector<String> versions;
versions.push_back("");
cluster_render.cluster_render_shader.initialize(versions, defines);
cluster_render.shader_version = cluster_render.cluster_render_shader.version_create();
cluster_render.shader = cluster_render.cluster_render_shader.version_get_shader(cluster_render.shader_version, 0);
cluster_render.shader_pipelines[ClusterRender::PIPELINE_NORMAL] = RD::get_singleton()->render_pipeline_create(cluster_render.shader, fb_format, vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rasterization_state, RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
RD::PipelineMultisampleState ms;
ms.sample_count = RD::TEXTURE_SAMPLES_4;
cluster_render.shader_pipelines[ClusterRender::PIPELINE_MSAA] = RD::get_singleton()->render_pipeline_create(cluster_render.shader, fb_format, vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rasterization_state, ms, RD::PipelineDepthStencilState(), blend_state, 0);
}
{
Vector<String> versions;
versions.push_back("");
cluster_store.cluster_store_shader.initialize(versions);
cluster_store.shader_version = cluster_store.cluster_store_shader.version_create();
cluster_store.shader = cluster_store.cluster_store_shader.version_get_shader(cluster_store.shader_version, 0);
cluster_store.shader_pipeline = RD::get_singleton()->compute_pipeline_create(cluster_store.shader);
}
{
Vector<String> versions;
versions.push_back("");
cluster_debug.cluster_debug_shader.initialize(versions);
cluster_debug.shader_version = cluster_debug.cluster_debug_shader.version_create();
cluster_debug.shader = cluster_debug.cluster_debug_shader.version_get_shader(cluster_debug.shader_version, 0);
cluster_debug.shader_pipeline = RD::get_singleton()->compute_pipeline_create(cluster_debug.shader);
}
{ // Sphere mesh data.
static const uint32_t icosphere_vertex_count = 42;
static const float icosphere_vertices[icosphere_vertex_count * 3] = {
0, 0, -1, 0.7236073, -0.5257253, -0.4472195, -0.276388, -0.8506492, -0.4472199, -0.8944262, 0, -0.4472156, -0.276388, 0.8506492, -0.4472199, 0.7236073, 0.5257253, -0.4472195, 0.276388, -0.8506492, 0.4472199, -0.7236073, -0.5257253, 0.4472195, -0.7236073, 0.5257253, 0.4472195, 0.276388, 0.8506492, 0.4472199, 0.8944262, 0, 0.4472156, 0, 0, 1, -0.1624555, -0.4999952, -0.8506544, 0.4253227, -0.3090114, -0.8506542, 0.2628688, -0.8090116, -0.5257377, 0.8506479, 0, -0.5257359, 0.4253227, 0.3090114, -0.8506542, -0.5257298, 0, -0.8506517, -0.6881894, -0.4999969, -0.5257362, -0.1624555, 0.4999952, -0.8506544, -0.6881894, 0.4999969, -0.5257362, 0.2628688, 0.8090116, -0.5257377, 0.9510579, -0.3090126, 0, 0.9510579, 0.3090126, 0, 0, -1, 0, 0.5877856, -0.8090167, 0, -0.9510579, -0.3090126, 0, -0.5877856, -0.8090167, 0, -0.5877856, 0.8090167, 0, -0.9510579, 0.3090126, 0, 0.5877856, 0.8090167, 0, 0, 1, 0, 0.6881894, -0.4999969, 0.5257362, -0.2628688, -0.8090116, 0.5257377, -0.8506479, 0, 0.5257359, -0.2628688, 0.8090116, 0.5257377, 0.6881894, 0.4999969, 0.5257362, 0.1624555, -0.4999952, 0.8506544, 0.5257298, 0, 0.8506517, -0.4253227, -0.3090114, 0.8506542, -0.4253227, 0.3090114, 0.8506542, 0.1624555, 0.4999952, 0.8506544
};
static const uint32_t icosphere_triangle_count = 80;
static const uint16_t icosphere_triangle_indices[icosphere_triangle_count * 3] = {
0, 13, 12, 1, 13, 15, 0, 12, 17, 0, 17, 19, 0, 19, 16, 1, 15, 22, 2, 14, 24, 3, 18, 26, 4, 20, 28, 5, 21, 30, 1, 22, 25, 2, 24, 27, 3, 26, 29, 4, 28, 31, 5, 30, 23, 6, 32, 37, 7, 33, 39, 8, 34, 40, 9, 35, 41, 10, 36, 38, 38, 41, 11, 38, 36, 41, 36, 9, 41, 41, 40, 11, 41, 35, 40, 35, 8, 40, 40, 39, 11, 40, 34, 39, 34, 7, 39, 39, 37, 11, 39, 33, 37, 33, 6, 37, 37, 38, 11, 37, 32, 38, 32, 10, 38, 23, 36, 10, 23, 30, 36, 30, 9, 36, 31, 35, 9, 31, 28, 35, 28, 8, 35, 29, 34, 8, 29, 26, 34, 26, 7, 34, 27, 33, 7, 27, 24, 33, 24, 6, 33, 25, 32, 6, 25, 22, 32, 22, 10, 32, 30, 31, 9, 30, 21, 31, 21, 4, 31, 28, 29, 8, 28, 20, 29, 20, 3, 29, 26, 27, 7, 26, 18, 27, 18, 2, 27, 24, 25, 6, 24, 14, 25, 14, 1, 25, 22, 23, 10, 22, 15, 23, 15, 5, 23, 16, 21, 5, 16, 19, 21, 19, 4, 21, 19, 20, 4, 19, 17, 20, 17, 3, 20, 17, 18, 3, 17, 12, 18, 12, 2, 18, 15, 16, 5, 15, 13, 16, 13, 0, 16, 12, 14, 2, 12, 13, 14, 13, 1, 14
};
Vector<uint8_t> vertex_data;
vertex_data.resize(sizeof(float) * icosphere_vertex_count * 3);
memcpy(vertex_data.ptrw(), icosphere_vertices, vertex_data.size());
sphere_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data);
Vector<uint8_t> index_data;
index_data.resize(sizeof(uint16_t) * icosphere_triangle_count * 3);
memcpy(index_data.ptrw(), icosphere_triangle_indices, index_data.size());
sphere_index_buffer = RD::get_singleton()->index_buffer_create(icosphere_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT16, index_data);
Vector<RID> buffers;
buffers.push_back(sphere_vertex_buffer);
sphere_vertex_array = RD::get_singleton()->vertex_array_create(icosphere_vertex_count, vertex_format, buffers);
sphere_index_array = RD::get_singleton()->index_array_create(sphere_index_buffer, 0, icosphere_triangle_count * 3);
float min_d = 1e20;
for (uint32_t i = 0; i < icosphere_triangle_count; i++) {
Vector3 vertices[3];
for (uint32_t j = 0; j < 3; j++) {
uint32_t index = icosphere_triangle_indices[i * 3 + j];
for (uint32_t k = 0; k < 3; k++) {
vertices[j][k] = icosphere_vertices[index * 3 + k];
}
}
Plane p(vertices[0], vertices[1], vertices[2]);
min_d = MIN(Math::abs(p.d), min_d);
}
sphere_overfit = 1.0 / min_d;
}
{ // Cone mesh data.
static const uint32_t cone_vertex_count = 99;
static const float cone_vertices[cone_vertex_count * 3] = {
0, 1, -1, 0.1950903, 0.9807853, -1, 0.3826835, 0.9238795, -1, 0.5555703, 0.8314696, -1, 0.7071068, 0.7071068, -1, 0.8314697, 0.5555702, -1, 0.9238795, 0.3826834, -1, 0.9807853, 0.1950903, -1, 1, 0, -1, 0.9807853, -0.1950902, -1, 0.9238796, -0.3826833, -1, 0.8314697, -0.5555702, -1, 0.7071068, -0.7071068, -1, 0.5555702, -0.8314697, -1, 0.3826833, -0.9238796, -1, 0.1950901, -0.9807853, -1, -3.25841e-7, -1, -1, -0.1950907, -0.9807852, -1, -0.3826839, -0.9238793, -1, -0.5555707, -0.8314693, -1, -0.7071073, -0.7071063, -1, -0.83147, -0.5555697, -1, -0.9238799, -0.3826827, -1, 0, 0, 0, -0.9807854, -0.1950894, -1, -1, 9.65599e-7, -1, -0.9807851, 0.1950913, -1, -0.9238791, 0.3826845, -1, -0.8314689, 0.5555713, -1, -0.7071059, 0.7071077, -1, -0.5555691, 0.8314704, -1, -0.3826821, 0.9238801, -1, -0.1950888, 0.9807856, -1
};
static const uint32_t cone_triangle_count = 62;
static const uint16_t cone_triangle_indices[cone_triangle_count * 3] = {
0, 23, 1, 1, 23, 2, 2, 23, 3, 3, 23, 4, 4, 23, 5, 5, 23, 6, 6, 23, 7, 7, 23, 8, 8, 23, 9, 9, 23, 10, 10, 23, 11, 11, 23, 12, 12, 23, 13, 13, 23, 14, 14, 23, 15, 15, 23, 16, 16, 23, 17, 17, 23, 18, 18, 23, 19, 19, 23, 20, 20, 23, 21, 21, 23, 22, 22, 23, 24, 24, 23, 25, 25, 23, 26, 26, 23, 27, 27, 23, 28, 28, 23, 29, 29, 23, 30, 30, 23, 31, 31, 23, 32, 32, 23, 0, 7, 15, 24, 32, 0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 3, 6, 7, 3, 7, 8, 9, 9, 10, 7, 10, 11, 7, 11, 12, 15, 12, 13, 15, 13, 14, 15, 15, 16, 17, 17, 18, 19, 19, 20, 24, 20, 21, 24, 21, 22, 24, 24, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, 32, 1, 3, 15, 17, 24, 17, 19, 24, 24, 26, 32, 26, 28, 32, 28, 30, 32, 32, 3, 7, 7, 11, 15, 32, 7, 24
};
Vector<uint8_t> vertex_data;
vertex_data.resize(sizeof(float) * cone_vertex_count * 3);
memcpy(vertex_data.ptrw(), cone_vertices, vertex_data.size());
cone_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data);
Vector<uint8_t> index_data;
index_data.resize(sizeof(uint16_t) * cone_triangle_count * 3);
memcpy(index_data.ptrw(), cone_triangle_indices, index_data.size());
cone_index_buffer = RD::get_singleton()->index_buffer_create(cone_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT16, index_data);
Vector<RID> buffers;
buffers.push_back(cone_vertex_buffer);
cone_vertex_array = RD::get_singleton()->vertex_array_create(cone_vertex_count, vertex_format, buffers);
cone_index_array = RD::get_singleton()->index_array_create(cone_index_buffer, 0, cone_triangle_count * 3);
float min_d = 1e20;
for (uint32_t i = 0; i < cone_triangle_count; i++) {
Vector3 vertices[3];
int32_t zero_index = -1;
for (uint32_t j = 0; j < 3; j++) {
uint32_t index = cone_triangle_indices[i * 3 + j];
for (uint32_t k = 0; k < 3; k++) {
vertices[j][k] = cone_vertices[index * 3 + k];
}
if (vertices[j] == Vector3()) {
zero_index = j;
}
}
if (zero_index != -1) {
Vector3 a = vertices[(zero_index + 1) % 3];
Vector3 b = vertices[(zero_index + 2) % 3];
Vector3 c = a + Vector3(0, 0, 1);
Plane p(a, b, c);
min_d = MIN(Math::abs(p.d), min_d);
}
}
cone_overfit = 1.0 / min_d;
}
{ // Box mesh data.
static const uint32_t box_vertex_count = 8;
static const float box_vertices[box_vertex_count * 3] = {
-1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1
};
static const uint32_t box_triangle_count = 12;
static const uint16_t box_triangle_indices[box_triangle_count * 3] = {
1, 2, 0, 3, 6, 2, 7, 4, 6, 5, 0, 4, 6, 0, 2, 3, 5, 7, 1, 3, 2, 3, 7, 6, 7, 5, 4, 5, 1, 0, 6, 4, 0, 3, 1, 5
};
Vector<uint8_t> vertex_data;
vertex_data.resize(sizeof(float) * box_vertex_count * 3);
memcpy(vertex_data.ptrw(), box_vertices, vertex_data.size());
box_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data);
Vector<uint8_t> index_data;
index_data.resize(sizeof(uint16_t) * box_triangle_count * 3);
memcpy(index_data.ptrw(), box_triangle_indices, index_data.size());
box_index_buffer = RD::get_singleton()->index_buffer_create(box_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT16, index_data);
Vector<RID> buffers;
buffers.push_back(box_vertex_buffer);
box_vertex_array = RD::get_singleton()->vertex_array_create(box_vertex_count, vertex_format, buffers);
box_index_array = RD::get_singleton()->index_array_create(box_index_buffer, 0, box_triangle_count * 3);
}
}
ClusterBuilderSharedDataRD::~ClusterBuilderSharedDataRD() {
RD::get_singleton()->free(sphere_vertex_buffer);
RD::get_singleton()->free(sphere_index_buffer);
RD::get_singleton()->free(cone_vertex_buffer);
RD::get_singleton()->free(cone_index_buffer);
RD::get_singleton()->free(box_vertex_buffer);
RD::get_singleton()->free(box_index_buffer);
cluster_render.cluster_render_shader.version_free(cluster_render.shader_version);
cluster_store.cluster_store_shader.version_free(cluster_store.shader_version);
cluster_debug.cluster_debug_shader.version_free(cluster_debug.shader_version);
}
/////////////////////////////
void ClusterBuilderRD::_clear() {
if (cluster_buffer.is_null()) {
return;
}
RD::get_singleton()->free(cluster_buffer);
RD::get_singleton()->free(cluster_render_buffer);
RD::get_singleton()->free(element_buffer);
cluster_buffer = RID();
cluster_render_buffer = RID();
element_buffer = RID();
memfree(render_elements);
render_elements = nullptr;
render_element_max = 0;
render_element_count = 0;
RD::get_singleton()->free(framebuffer);
framebuffer = RID();
cluster_render_uniform_set = RID();
cluster_store_uniform_set = RID();
}
void ClusterBuilderRD::setup(Size2i p_screen_size, uint32_t p_max_elements, RID p_depth_buffer, RID p_depth_buffer_sampler, RID p_color_buffer) {
ERR_FAIL_COND(p_max_elements == 0);
ERR_FAIL_COND(p_screen_size.x < 1);
ERR_FAIL_COND(p_screen_size.y < 1);
_clear();
screen_size = p_screen_size;
cluster_screen_size.width = Math::division_round_up((uint32_t)p_screen_size.width, cluster_size);
cluster_screen_size.height = Math::division_round_up((uint32_t)p_screen_size.height, cluster_size);
max_elements_by_type = p_max_elements;
if (max_elements_by_type % 32) { // Needs to be aligned to 32.
max_elements_by_type += 32 - (max_elements_by_type % 32);
}
cluster_buffer_size = cluster_screen_size.x * cluster_screen_size.y * (max_elements_by_type / 32 + 32) * ELEMENT_TYPE_MAX * 4;
render_element_max = max_elements_by_type * ELEMENT_TYPE_MAX;
uint32_t element_tag_bits_size = render_element_max / 32;
uint32_t element_tag_depth_bits_size = render_element_max;
cluster_render_buffer_size = cluster_screen_size.x * cluster_screen_size.y * (element_tag_bits_size + element_tag_depth_bits_size) * 4; // Tag bits (element was used) and tag depth (depth range in which it was used).
cluster_render_buffer = RD::get_singleton()->storage_buffer_create(cluster_render_buffer_size);
cluster_buffer = RD::get_singleton()->storage_buffer_create(cluster_buffer_size);
render_elements = static_cast<RenderElementData *>(memalloc(sizeof(RenderElementData) * render_element_max));
render_element_count = 0;
element_buffer = RD::get_singleton()->storage_buffer_create(sizeof(RenderElementData) * render_element_max);
uint32_t div_value = 1 << divisor;
if (use_msaa) {
framebuffer = RD::get_singleton()->framebuffer_create_empty(p_screen_size / div_value, RD::TEXTURE_SAMPLES_4);
} else {
framebuffer = RD::get_singleton()->framebuffer_create_empty(p_screen_size / div_value);
}
{
Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 1;
u.append_id(state_uniform);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 2;
u.append_id(element_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 3;
u.append_id(cluster_render_buffer);
uniforms.push_back(u);
}
cluster_render_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shared->cluster_render.shader, 0);
}
{
Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 1;
u.append_id(cluster_render_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 2;
u.append_id(cluster_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 3;
u.append_id(element_buffer);
uniforms.push_back(u);
}
cluster_store_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shared->cluster_store.shader, 0);
}
if (p_color_buffer.is_valid()) {
Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 1;
u.append_id(cluster_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 2;
u.append_id(p_color_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 3;
u.append_id(p_depth_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
u.binding = 4;
u.append_id(p_depth_buffer_sampler);
uniforms.push_back(u);
}
debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shared->cluster_debug.shader, 0);
} else {
debug_uniform_set = RID();
}
}
void ClusterBuilderRD::begin(const Transform3D &p_view_transform, const Projection &p_cam_projection, bool p_flip_y) {
view_xform = p_view_transform.affine_inverse();
projection = p_cam_projection;
z_near = projection.get_z_near();
z_far = projection.get_z_far();
camera_orthogonal = p_cam_projection.is_orthogonal();
adjusted_projection = projection;
if (!camera_orthogonal) {
adjusted_projection.adjust_perspective_znear(0.0001);
}
Projection correction;
correction.set_depth_correction(p_flip_y);
projection = correction * projection;
adjusted_projection = correction * adjusted_projection;
// Reset counts.
render_element_count = 0;
for (uint32_t i = 0; i < ELEMENT_TYPE_MAX; i++) {
cluster_count_by_type[i] = 0;
}
}
void ClusterBuilderRD::bake_cluster() {
RENDER_TIMESTAMP("> Bake 3D Cluster");
RD::get_singleton()->draw_command_begin_label("Bake Light Cluster");
// Clear cluster buffer.
RD::get_singleton()->buffer_clear(cluster_buffer, 0, cluster_buffer_size);
if (render_element_count > 0) {
// Clear render buffer.
RD::get_singleton()->buffer_clear(cluster_render_buffer, 0, cluster_render_buffer_size);
{ // Fill state uniform.
StateUniform state;
RendererRD::MaterialStorage::store_camera(adjusted_projection, state.projection);
state.inv_z_far = 1.0 / z_far;
state.screen_to_clusters_shift = get_shift_from_power_of_2(cluster_size);
state.screen_to_clusters_shift -= divisor; //screen is smaller, shift one less
state.cluster_screen_width = cluster_screen_size.x;
state.cluster_depth_offset = (render_element_max / 32);
state.cluster_data_size = state.cluster_depth_offset + render_element_max;
RD::get_singleton()->buffer_update(state_uniform, 0, sizeof(StateUniform), &state);
}
// Update instances.
RD::get_singleton()->buffer_update(element_buffer, 0, sizeof(RenderElementData) * render_element_count, render_elements);
RENDER_TIMESTAMP("Render 3D Cluster Elements");
// Render elements.
{
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD);
ClusterBuilderSharedDataRD::ClusterRender::PushConstant push_constant = {};
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shared->cluster_render.shader_pipelines[use_msaa ? ClusterBuilderSharedDataRD::ClusterRender::PIPELINE_MSAA : ClusterBuilderSharedDataRD::ClusterRender::PIPELINE_NORMAL]);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, cluster_render_uniform_set, 0);
for (uint32_t i = 0; i < render_element_count;) {
push_constant.base_index = i;
switch (render_elements[i].type) {
case ELEMENT_TYPE_OMNI_LIGHT: {
RD::get_singleton()->draw_list_bind_vertex_array(draw_list, shared->sphere_vertex_array);
RD::get_singleton()->draw_list_bind_index_array(draw_list, shared->sphere_index_array);
} break;
case ELEMENT_TYPE_SPOT_LIGHT: {
// If the spot angle is above a certain threshold, use a sphere instead of a cone for building the clusters
// since the cone gets too flat/large (spot angle close to 90 degrees) or
// can't even cover the affected area of the light (spot angle above 90 degrees).
if (render_elements[i].has_wide_spot_angle) {
RD::get_singleton()->draw_list_bind_vertex_array(draw_list, shared->sphere_vertex_array);
RD::get_singleton()->draw_list_bind_index_array(draw_list, shared->sphere_index_array);
} else {
RD::get_singleton()->draw_list_bind_vertex_array(draw_list, shared->cone_vertex_array);
RD::get_singleton()->draw_list_bind_index_array(draw_list, shared->cone_index_array);
}
} break;
case ELEMENT_TYPE_DECAL:
case ELEMENT_TYPE_REFLECTION_PROBE: {
RD::get_singleton()->draw_list_bind_vertex_array(draw_list, shared->box_vertex_array);
RD::get_singleton()->draw_list_bind_index_array(draw_list, shared->box_index_array);
} break;
}
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ClusterBuilderSharedDataRD::ClusterRender::PushConstant));
uint32_t instances = 1;
RD::get_singleton()->draw_list_draw(draw_list, true, instances);
i += instances;
}
RD::get_singleton()->draw_list_end();
}
// Store elements.
RENDER_TIMESTAMP("Pack 3D Cluster Elements");
{
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shared->cluster_store.shader_pipeline);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cluster_store_uniform_set, 0);
ClusterBuilderSharedDataRD::ClusterStore::PushConstant push_constant;
push_constant.cluster_render_data_size = render_element_max / 32 + render_element_max;
push_constant.max_render_element_count_div_32 = render_element_max / 32;
push_constant.cluster_screen_size[0] = cluster_screen_size.x;
push_constant.cluster_screen_size[1] = cluster_screen_size.y;
push_constant.render_element_count_div_32 = Math::division_round_up(render_element_count, 32U);
push_constant.max_cluster_element_count_div_32 = max_elements_by_type / 32;
push_constant.pad1 = 0;
push_constant.pad2 = 0;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ClusterBuilderSharedDataRD::ClusterStore::PushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, cluster_screen_size.x, cluster_screen_size.y, 1);
RD::get_singleton()->compute_list_end();
}
}
RENDER_TIMESTAMP("< Bake 3D Cluster");
RD::get_singleton()->draw_command_end_label();
}
void ClusterBuilderRD::debug(ElementType p_element) {
ERR_FAIL_COND(debug_uniform_set.is_null());
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shared->cluster_debug.shader_pipeline);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, debug_uniform_set, 0);
ClusterBuilderSharedDataRD::ClusterDebug::PushConstant push_constant;
push_constant.screen_size[0] = screen_size.x;
push_constant.screen_size[1] = screen_size.y;
push_constant.cluster_screen_size[0] = cluster_screen_size.x;
push_constant.cluster_screen_size[1] = cluster_screen_size.y;
push_constant.cluster_shift = get_shift_from_power_of_2(cluster_size);
push_constant.cluster_type = p_element;
push_constant.orthogonal = camera_orthogonal;
push_constant.z_far = z_far;
push_constant.z_near = z_near;
push_constant.max_cluster_element_count_div_32 = max_elements_by_type / 32;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ClusterBuilderSharedDataRD::ClusterDebug::PushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, screen_size.x, screen_size.y, 1);
RD::get_singleton()->compute_list_end();
}
RID ClusterBuilderRD::get_cluster_buffer() const {
return cluster_buffer;
}
uint32_t ClusterBuilderRD::get_cluster_size() const {
return cluster_size;
}
uint32_t ClusterBuilderRD::get_max_cluster_elements() const {
return max_elements_by_type;
}
void ClusterBuilderRD::set_shared(ClusterBuilderSharedDataRD *p_shared) {
shared = p_shared;
}
ClusterBuilderRD::ClusterBuilderRD() {
state_uniform = RD::get_singleton()->uniform_buffer_create(sizeof(StateUniform));
}
ClusterBuilderRD::~ClusterBuilderRD() {
_clear();
RD::get_singleton()->free(state_uniform);
}

View file

@ -0,0 +1,391 @@
/**************************************************************************/
/* cluster_builder_rd.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 CLUSTER_BUILDER_RD_H
#define CLUSTER_BUILDER_RD_H
#include "servers/rendering/renderer_rd/shaders/cluster_debug.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/cluster_render.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/cluster_store.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
class ClusterBuilderSharedDataRD {
friend class ClusterBuilderRD;
RID sphere_vertex_buffer;
RID sphere_vertex_array;
RID sphere_index_buffer;
RID sphere_index_array;
float sphere_overfit = 0.0; // Because an icosphere is not a perfect sphere, we need to enlarge it to cover the sphere area.
RID cone_vertex_buffer;
RID cone_vertex_array;
RID cone_index_buffer;
RID cone_index_array;
float cone_overfit = 0.0; // Because an cone mesh is not a perfect cone, we need to enlarge it to cover the actual cone area.
RID box_vertex_buffer;
RID box_vertex_array;
RID box_index_buffer;
RID box_index_array;
enum Divisor {
DIVISOR_1,
DIVISOR_2,
DIVISOR_4,
};
struct ClusterRender {
struct PushConstant {
uint32_t base_index;
uint32_t pad0;
uint32_t pad1;
uint32_t pad2;
};
ClusterRenderShaderRD cluster_render_shader;
RID shader_version;
RID shader;
enum PipelineVersion {
PIPELINE_NORMAL,
PIPELINE_MSAA,
PIPELINE_MAX
};
RID shader_pipelines[PIPELINE_MAX];
} cluster_render;
struct ClusterStore {
struct PushConstant {
uint32_t cluster_render_data_size; // how much data for a single cluster takes
uint32_t max_render_element_count_div_32; // divided by 32
uint32_t cluster_screen_size[2];
uint32_t render_element_count_div_32; // divided by 32
uint32_t max_cluster_element_count_div_32; // divided by 32
uint32_t pad1;
uint32_t pad2;
};
ClusterStoreShaderRD cluster_store_shader;
RID shader_version;
RID shader;
RID shader_pipeline;
} cluster_store;
struct ClusterDebug {
struct PushConstant {
uint32_t screen_size[2];
uint32_t cluster_screen_size[2];
uint32_t cluster_shift;
uint32_t cluster_type;
float z_near;
float z_far;
uint32_t orthogonal;
uint32_t max_cluster_element_count_div_32;
uint32_t pad1;
uint32_t pad2;
};
ClusterDebugShaderRD cluster_debug_shader;
RID shader_version;
RID shader;
RID shader_pipeline;
} cluster_debug;
public:
ClusterBuilderSharedDataRD();
~ClusterBuilderSharedDataRD();
};
class ClusterBuilderRD {
public:
static constexpr float WIDE_SPOT_ANGLE_THRESHOLD_DEG = 60.0f;
enum LightType {
LIGHT_TYPE_OMNI,
LIGHT_TYPE_SPOT
};
enum BoxType {
BOX_TYPE_REFLECTION_PROBE,
BOX_TYPE_DECAL,
};
enum ElementType {
ELEMENT_TYPE_OMNI_LIGHT,
ELEMENT_TYPE_SPOT_LIGHT,
ELEMENT_TYPE_DECAL,
ELEMENT_TYPE_REFLECTION_PROBE,
ELEMENT_TYPE_MAX,
};
private:
ClusterBuilderSharedDataRD *shared = nullptr;
struct RenderElementData {
uint32_t type; // 0-4
uint32_t touches_near;
uint32_t touches_far;
uint32_t original_index;
float transform_inv[12]; // Transposed transform for less space.
float scale[3];
uint32_t has_wide_spot_angle;
}; // Keep aligned to 32 bytes.
uint32_t cluster_count_by_type[ELEMENT_TYPE_MAX] = {};
uint32_t max_elements_by_type = 0;
RenderElementData *render_elements = nullptr;
uint32_t render_element_count = 0;
uint32_t render_element_max = 0;
Transform3D view_xform;
Projection adjusted_projection;
Projection projection;
float z_far = 0;
float z_near = 0;
bool camera_orthogonal = false;
enum Divisor {
DIVISOR_1,
DIVISOR_2,
DIVISOR_4,
};
uint32_t cluster_size = 32;
bool use_msaa = true;
Divisor divisor = DIVISOR_4;
Size2i screen_size;
Size2i cluster_screen_size;
RID framebuffer;
RID cluster_render_buffer; // Used for creating.
RID cluster_buffer; // Used for rendering.
RID element_buffer; // Used for storing, to hint element touches far plane or near plane.
uint32_t cluster_render_buffer_size = 0;
uint32_t cluster_buffer_size = 0;
RID cluster_render_uniform_set;
RID cluster_store_uniform_set;
// Persistent data.
void _clear();
struct StateUniform {
float projection[16];
float inv_z_far;
uint32_t screen_to_clusters_shift; // Shift to obtain coordinates in block indices.
uint32_t cluster_screen_width;
uint32_t cluster_data_size; // How much data is needed for a single cluster.
uint32_t cluster_depth_offset;
uint32_t pad0;
uint32_t pad1;
uint32_t pad2;
};
RID state_uniform;
RID debug_uniform_set;
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 Transform3D &p_view_transform, const Projection &p_cam_projection, bool p_flip_y);
_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.
}
if (p_type == LIGHT_TYPE_SPOT && cluster_count_by_type[ELEMENT_TYPE_SPOT_LIGHT] == max_elements_by_type) {
return; // Max number elements reached.
}
RenderElementData &e = render_elements[render_element_count];
Transform3D xform = view_xform * p_transform;
float radius = xform.basis.get_uniform_scale();
if (radius < 0.98 || radius > 1.02) {
xform.basis.orthonormalize();
}
radius *= p_radius;
if (p_type == LIGHT_TYPE_OMNI) {
radius *= shared->sphere_overfit; // Overfit icosphere.
float depth = -xform.origin.z;
if (camera_orthogonal) {
e.touches_near = (depth - radius) < z_near;
} else {
// Contains camera inside light.
float radius2 = radius * shared->sphere_overfit; // Overfit again for outer size (camera may be outside actual sphere but behind an icosphere vertex)
e.touches_near = xform.origin.length_squared() < radius2 * radius2;
}
e.touches_far = (depth + radius) > z_far;
e.scale[0] = radius;
e.scale[1] = radius;
e.scale[2] = radius;
e.type = ELEMENT_TYPE_OMNI_LIGHT;
e.original_index = cluster_count_by_type[ELEMENT_TYPE_OMNI_LIGHT];
RendererRD::MaterialStorage::store_transform_transposed_3x4(xform, e.transform_inv);
cluster_count_by_type[ELEMENT_TYPE_OMNI_LIGHT]++;
} else /*LIGHT_TYPE_SPOT */ {
radius *= shared->cone_overfit; // Overfit icosphere
real_t len = Math::tan(Math::deg_to_rad(p_spot_aperture)) * radius;
// Approximate, probably better to use a cone support function.
float max_d = -1e20;
float min_d = 1e20;
#define CONE_MINMAX(m_x, m_y) \
{ \
float d = -xform.xform(Vector3(len * m_x, len * m_y, -radius)).z; \
min_d = MIN(d, min_d); \
max_d = MAX(d, max_d); \
}
CONE_MINMAX(1, 1);
CONE_MINMAX(-1, 1);
CONE_MINMAX(-1, -1);
CONE_MINMAX(1, -1);
if (camera_orthogonal) {
e.touches_near = min_d < z_near;
} else {
Plane base_plane(-xform.basis.get_column(Vector3::AXIS_Z), xform.origin);
float dist = base_plane.distance_to(Vector3());
if (dist >= 0 && dist < radius) {
// Contains camera inside light, check angle.
float angle = Math::rad_to_deg(Math::acos((-xform.origin.normalized()).dot(-xform.basis.get_column(Vector3::AXIS_Z))));
e.touches_near = angle < p_spot_aperture * 1.05; //overfit aperture a little due to cone overfit
} else {
e.touches_near = false;
}
}
e.touches_far = max_d > z_far;
// If the spot angle is above the threshold, use a sphere instead of a cone for building the clusters
// since the cone gets too flat/large (spot angle close to 90 degrees) or
// can't even cover the affected area of the light (spot angle above 90 degrees).
if (p_spot_aperture > WIDE_SPOT_ANGLE_THRESHOLD_DEG) {
e.scale[0] = radius;
e.scale[1] = radius;
e.scale[2] = radius;
e.has_wide_spot_angle = true;
} else {
e.scale[0] = len * shared->cone_overfit;
e.scale[1] = len * shared->cone_overfit;
e.scale[2] = radius;
e.has_wide_spot_angle = false;
}
e.type = ELEMENT_TYPE_SPOT_LIGHT;
e.original_index = cluster_count_by_type[ELEMENT_TYPE_SPOT_LIGHT]; // Use omni light since they share index.
RendererRD::MaterialStorage::store_transform_transposed_3x4(xform, e.transform_inv);
cluster_count_by_type[ELEMENT_TYPE_SPOT_LIGHT]++;
}
render_element_count++;
}
_FORCE_INLINE_ void add_box(BoxType p_box_type, const Transform3D &p_transform, const Vector3 &p_half_size) {
if (p_box_type == BOX_TYPE_DECAL && cluster_count_by_type[ELEMENT_TYPE_DECAL] == max_elements_by_type) {
return; // Max number elements reached.
}
if (p_box_type == BOX_TYPE_REFLECTION_PROBE && cluster_count_by_type[ELEMENT_TYPE_REFLECTION_PROBE] == max_elements_by_type) {
return; // Max number elements reached.
}
RenderElementData &e = render_elements[render_element_count];
Transform3D xform = view_xform * p_transform;
// Extract scale and scale the matrix by it, makes things simpler.
Vector3 scale = p_half_size;
for (uint32_t i = 0; i < 3; i++) {
float s = xform.basis.rows[i].length();
scale[i] *= s;
xform.basis.rows[i] /= s;
};
float box_depth = Math::abs(xform.basis.xform_inv(Vector3(0, 0, -1)).dot(scale));
float depth = -xform.origin.z;
if (camera_orthogonal) {
e.touches_near = depth - box_depth < z_near;
} else {
// Contains camera inside box.
Vector3 inside = xform.xform_inv(Vector3(0, 0, 0)).abs();
e.touches_near = inside.x < scale.x && inside.y < scale.y && inside.z < scale.z;
}
e.touches_far = depth + box_depth > z_far;
e.scale[0] = scale.x;
e.scale[1] = scale.y;
e.scale[2] = scale.z;
e.type = (p_box_type == BOX_TYPE_DECAL) ? ELEMENT_TYPE_DECAL : ELEMENT_TYPE_REFLECTION_PROBE;
e.original_index = cluster_count_by_type[e.type];
RendererRD::MaterialStorage::store_transform_transposed_3x4(xform, e.transform_inv);
cluster_count_by_type[e.type]++;
render_element_count++;
}
void bake_cluster();
void debug(ElementType p_element);
RID get_cluster_buffer() const;
uint32_t get_cluster_size() const;
uint32_t get_max_cluster_elements() const;
void set_shared(ClusterBuilderSharedDataRD *p_shared);
ClusterBuilderRD();
~ClusterBuilderRD();
};
#endif // CLUSTER_BUILDER_RD_H

View file

@ -0,0 +1,34 @@
#!/usr/bin/env python
Import("env")
env_effects = env.Clone()
# Thirdparty source files
thirdparty_obj = []
thirdparty_dir = "#thirdparty/amd-fsr2/"
thirdparty_sources = ["ffx_assert.cpp", "ffx_fsr2.cpp"]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_effects.Prepend(CPPPATH=[thirdparty_dir])
# This flag doesn't actually control anything GCC specific in FSR2. It determines
# if symbols should be exported, which is not required for Godot.
env_effects.Append(CPPDEFINES=["FFX_GCC"])
env_thirdparty = env_effects.Clone()
env_thirdparty.disable_warnings()
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
env.servers_sources += thirdparty_obj
# Godot source files
module_obj = []
env_effects.add_source_files(module_obj, "*.cpp")
env.servers_sources += module_obj
# Needed to force rebuilding the module files when the thirdparty library is updated.
env.Depends(module_obj, thirdparty_obj)

View file

@ -0,0 +1,499 @@
/**************************************************************************/
/* bokeh_dof.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "bokeh_dof.h"
#include "copy_effects.h"
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
#include "servers/rendering/rendering_server_default.h"
#include "servers/rendering/storage/camera_attributes_storage.h"
using namespace RendererRD;
BokehDOF::BokehDOF(bool p_prefer_raster_effects) {
prefer_raster_effects = p_prefer_raster_effects;
// 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_version = bokeh.raster_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++) {
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();
}
}
}
BokehDOF::~BokehDOF() {
if (prefer_raster_effects) {
bokeh.raster_shader.version_free(bokeh.shader_version);
} else {
bokeh.compute_shader.version_free(bokeh.shader_version);
}
}
void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, RID p_camera_attributes, 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 depth of field with the mobile renderer.");
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
bool dof_far = RSG::camera_attributes->camera_attributes_get_dof_far_enabled(p_camera_attributes);
float dof_far_begin = RSG::camera_attributes->camera_attributes_get_dof_far_distance(p_camera_attributes);
float dof_far_size = RSG::camera_attributes->camera_attributes_get_dof_far_transition(p_camera_attributes);
bool dof_near = RSG::camera_attributes->camera_attributes_get_dof_near_enabled(p_camera_attributes);
float dof_near_begin = RSG::camera_attributes->camera_attributes_get_dof_near_distance(p_camera_attributes);
float dof_near_size = RSG::camera_attributes->camera_attributes_get_dof_near_transition(p_camera_attributes);
float bokeh_size = RSG::camera_attributes->camera_attributes_get_dof_blur_amount(p_camera_attributes) * 64; // Base 64 pixel radius.
bool use_jitter = RSG::camera_attributes->camera_attributes_get_dof_blur_use_jitter();
RS::DOFBokehShape bokeh_shape = RSG::camera_attributes->camera_attributes_get_dof_blur_bokeh_shape();
RS::DOFBlurQuality blur_quality = RSG::camera_attributes->camera_attributes_get_dof_blur_quality();
// setup our push constant
memset(&bokeh.push_constant, 0, sizeof(BokehPushConstant));
bokeh.push_constant.blur_far_active = dof_far;
bokeh.push_constant.blur_far_begin = dof_far_begin;
bokeh.push_constant.blur_far_end = dof_far_begin + dof_far_size; // Only used with non-physically-based.
bokeh.push_constant.use_physical_far = dof_far_size < 0.0;
bokeh.push_constant.blur_size_far = bokeh_size; // Only used with physically-based.
bokeh.push_constant.blur_near_active = dof_near;
bokeh.push_constant.blur_near_begin = dof_near_begin;
bokeh.push_constant.blur_near_end = dof_near_begin - dof_near_size; // Only used with non-physically-based.
bokeh.push_constant.use_physical_near = dof_near_size < 0.0;
bokeh.push_constant.blur_size_near = bokeh_size; // Only used with physically-based.
bokeh.push_constant.use_jitter = use_jitter;
bokeh.push_constant.jitter_seed = Math::randf() * 1000.0;
bokeh.push_constant.z_near = p_cam_znear;
bokeh.push_constant.z_far = p_cam_zfar;
bokeh.push_constant.orthogonal = p_cam_orthogonal;
bokeh.push_constant.blur_size = (dof_near_size < 0.0 && dof_far_size < 0.0) ? 32 : bokeh_size; // Cap with physically-based to keep performance reasonable.
bokeh.push_constant.second_pass = false;
bokeh.push_constant.half_size = false;
bokeh.push_constant.blur_scale = 0.5;
// setup our uniforms
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RD::Uniform u_base_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.base_texture }));
RD::Uniform u_depth_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.depth_texture }));
RD::Uniform u_secondary_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.secondary_texture }));
RD::Uniform u_half_texture0(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.half_texture[0] }));
RD::Uniform u_half_texture1(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.half_texture[1] }));
RD::Uniform u_base_image(RD::UNIFORM_TYPE_IMAGE, 0, p_buffers.base_texture);
RD::Uniform u_secondary_image(RD::UNIFORM_TYPE_IMAGE, 0, p_buffers.secondary_texture);
RD::Uniform u_half_image0(RD::UNIFORM_TYPE_IMAGE, 0, p_buffers.half_texture[0]);
RD::Uniform u_half_image1(RD::UNIFORM_TYPE_IMAGE, 0, p_buffers.half_texture[1]);
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
/* FIRST PASS */
// 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.
RID shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, BOKEH_GEN_BLUR_SIZE);
ERR_FAIL_COND(shader.is_null());
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, uniform_set_cache->get_cache(shader, 0, u_base_image), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_depth_texture), 1);
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_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
RD::get_singleton()->compute_list_add_barrier(compute_list);
if (bokeh_shape == RS::DOF_BOKEH_BOX || bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
//second pass
BokehMode mode = bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL;
shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[mode]);
static const int quality_samples[4] = { 6, 12, 12, 24 };
bokeh.push_constant.steps = quality_samples[blur_quality];
if (blur_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || blur_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, uniform_set_cache->get_cache(shader, 0, u_half_image0), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_base_texture), 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, uniform_set_cache->get_cache(shader, 0, u_secondary_image), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_base_texture), 1);
}
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, bokeh.push_constant.size[0], bokeh.push_constant.size[1], 1);
RD::get_singleton()->compute_list_add_barrier(compute_list);
//third pass
bokeh.push_constant.second_pass = true;
if (blur_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || blur_quality == RS::DOF_BLUR_QUALITY_LOW) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_half_image1), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_half_texture0), 1);
} else {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_base_image), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_secondary_texture), 1);
}
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, bokeh.push_constant.size[0], bokeh.push_constant.size[1], 1);
RD::get_singleton()->compute_list_add_barrier(compute_list);
if (blur_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || blur_quality == RS::DOF_BLUR_QUALITY_LOW) {
//forth pass, upscale for low quality
shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, BOKEH_COMPOSITE);
ERR_FAIL_COND(shader.is_null());
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, uniform_set_cache->get_cache(shader, 0, u_base_image), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_half_texture1), 1);
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_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
}
} else {
//circle
shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, BOKEH_GEN_BOKEH_CIRCULAR);
ERR_FAIL_COND(shader.is_null());
//second pass
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 };
bokeh.push_constant.steps = 0;
bokeh.push_constant.blur_scale = quality_scale[blur_quality];
//circle always runs in half size, otherwise too expensive
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_half_image0), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_base_texture), 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));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, bokeh.push_constant.size[0], bokeh.push_constant.size[1], 1);
RD::get_singleton()->compute_list_add_barrier(compute_list);
//circle is just one pass, then upscale
// upscale
shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, BOKEH_COMPOSITE);
ERR_FAIL_COND(shader.is_null());
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, uniform_set_cache->get_cache(shader, 0, u_base_image), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_half_texture0), 1);
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_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
}
RD::get_singleton()->compute_list_end();
}
void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attributes, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't blur-based depth of field with the clustered renderer.");
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
bool dof_far = RSG::camera_attributes->camera_attributes_get_dof_far_enabled(p_camera_attributes);
float dof_far_begin = RSG::camera_attributes->camera_attributes_get_dof_far_distance(p_camera_attributes);
float dof_far_size = RSG::camera_attributes->camera_attributes_get_dof_far_transition(p_camera_attributes);
bool dof_near = RSG::camera_attributes->camera_attributes_get_dof_near_enabled(p_camera_attributes);
float dof_near_begin = RSG::camera_attributes->camera_attributes_get_dof_near_distance(p_camera_attributes);
float dof_near_size = RSG::camera_attributes->camera_attributes_get_dof_near_transition(p_camera_attributes);
float bokeh_size = RSG::camera_attributes->camera_attributes_get_dof_blur_amount(p_camera_attributes) * 64; // Base 64 pixel radius.
RS::DOFBokehShape bokeh_shape = RSG::camera_attributes->camera_attributes_get_dof_blur_bokeh_shape();
RS::DOFBlurQuality blur_quality = RSG::camera_attributes->camera_attributes_get_dof_blur_quality();
// setup our base push constant
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 = bokeh_size;
// setup our uniforms
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RD::Uniform u_base_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.base_texture }));
RD::Uniform u_depth_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.depth_texture }));
RD::Uniform u_secondary_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.secondary_texture }));
RD::Uniform u_half_texture0(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.half_texture[0] }));
RD::Uniform u_half_texture1(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.half_texture[1] }));
RD::Uniform u_weight_texture0(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.weight_texture[0] }));
RD::Uniform u_weight_texture1(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.weight_texture[1] }));
RD::Uniform u_weight_texture2(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.weight_texture[2] }));
RD::Uniform u_weight_texture3(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.weight_texture[3] }));
if (dof_far || dof_near) {
if (dof_far) {
bokeh.push_constant.blur_far_active = true;
bokeh.push_constant.blur_far_begin = dof_far_begin;
bokeh.push_constant.blur_far_end = dof_far_begin + dof_far_size;
}
if (dof_near) {
bokeh.push_constant.blur_near_active = true;
bokeh.push_constant.blur_near_begin = dof_near_begin;
bokeh.push_constant.blur_near_end = dof_near_begin - dof_near_size;
}
{
// generate our depth data
RID shader = bokeh.raster_shader.version_get_shader(bokeh.shader_version, BOKEH_GEN_BLUR_SIZE);
ERR_FAIL_COND(shader.is_null());
RID framebuffer = p_buffers.base_weight_fb;
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, 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, uniform_set_cache->get_cache(shader, 0, u_depth_texture), 0);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
if (bokeh_shape == RS::DOF_BOKEH_BOX || bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
// double pass approach
BokehMode mode = bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL;
RID shader = bokeh.raster_shader.version_get_shader(bokeh.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
if (blur_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || blur_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[blur_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_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, 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, uniform_set_cache->get_cache(shader, 0, u_base_texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture0), 1);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
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 = bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX_NOWEIGHT : BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT;
shader = bokeh.raster_shader.version_get_shader(bokeh.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
}
bokeh.push_constant.second_pass = true;
framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[1] : p_buffers.base_fb;
RD::Uniform texture = bokeh.push_constant.half_size ? u_half_texture0 : u_secondary_texture;
RD::Uniform weight = bokeh.push_constant.half_size ? u_weight_texture2 : u_weight_texture1;
draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, 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, uniform_set_cache->get_cache(shader, 0, texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, weight), 1);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
if (bokeh.push_constant.half_size) {
// Compose pass
mode = BOKEH_COMPOSITE;
shader = bokeh.raster_shader.version_get_shader(bokeh.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
framebuffer = p_buffers.base_fb;
draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, 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, uniform_set_cache->get_cache(shader, 0, u_half_texture1), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture3), 1);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 2, u_weight_texture0), 2);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
} else {
// circular is a single pass approach
BokehMode mode = BOKEH_GEN_BOKEH_CIRCULAR;
RID shader = bokeh.raster_shader.version_get_shader(bokeh.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
{
// 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[blur_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_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, 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, uniform_set_cache->get_cache(shader, 0, u_base_texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture0), 1);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
if (bokeh.push_constant.half_size) {
// Compose
mode = BOKEH_COMPOSITE;
shader = bokeh.raster_shader.version_get_shader(bokeh.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
framebuffer = p_buffers.base_fb;
draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, 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, uniform_set_cache->get_cache(shader, 0, u_half_texture0), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture2), 1);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 2, u_weight_texture0), 2);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
} else {
CopyEffects::get_singleton()->copy_raster(p_buffers.secondary_texture, p_buffers.base_fb);
}
}
}
}

View file

@ -0,0 +1,125 @@
/**************************************************************************/
/* bokeh_dof.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 BOKEH_DOF_RD_H
#define BOKEH_DOF_RD_H
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
namespace RendererRD {
class BokehDOF {
private:
bool prefer_raster_effects;
struct BokehPushConstant {
uint32_t size[2];
float z_far;
float z_near;
uint32_t orthogonal;
float blur_size;
float blur_scale;
uint32_t steps;
uint32_t blur_near_active;
float blur_near_begin;
float blur_near_end;
uint32_t blur_far_active;
float blur_far_begin;
float blur_far_end;
uint32_t second_pass;
uint32_t half_size;
uint32_t use_jitter;
float jitter_seed;
uint32_t use_physical_near;
uint32_t use_physical_far;
float blur_size_near;
float blur_size_far;
uint32_t pad[2];
};
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
};
struct Bokeh {
BokehPushConstant push_constant;
BokehDofShaderRD compute_shader;
BokehDofRasterShaderRD raster_shader;
RID shader_version;
RID compute_pipelines[BOKEH_MAX];
PipelineCacheRD raster_pipelines[BOKEH_MAX];
} bokeh;
public:
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];
};
BokehDOF(bool p_prefer_raster_effects);
~BokehDOF();
void bokeh_dof_compute(const BokehBuffers &p_buffers, RID p_camera_attributes, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
void bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attributes, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
};
} // namespace RendererRD
#endif // BOKEH_DOF_RD_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,363 @@
/**************************************************************************/
/* copy_effects.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 COPY_EFFECTS_RD_H
#define COPY_EFFECTS_RD_H
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/blur_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/copy.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/cubemap_filter.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/cubemap_roughness.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
namespace RendererRD {
class CopyEffects {
private:
bool prefer_raster_effects;
// Blur raster shader
enum BlurRasterMode {
BLUR_MIPMAP,
BLUR_MODE_GAUSSIAN_BLUR,
BLUR_MODE_GAUSSIAN_GLOW,
BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE,
BLUR_MODE_COPY,
BLUR_MODE_SET_COLOR,
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_scale;
float luminance_multiplier;
float res1;
float res2;
float res3;
};
struct BlurRaster {
BlurRasterPushConstant push_constant;
BlurRasterShaderRD shader;
RID shader_version;
PipelineCacheRD pipelines[BLUR_MODE_MAX];
} blur_raster;
// Copy shader
enum CopyMode {
COPY_MODE_GAUSSIAN_COPY,
COPY_MODE_GAUSSIAN_COPY_8BIT,
COPY_MODE_GAUSSIAN_GLOW,
COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE,
COPY_MODE_SIMPLY_COPY,
COPY_MODE_SIMPLY_COPY_8BIT,
COPY_MODE_SIMPLY_COPY_DEPTH,
COPY_MODE_SET_COLOR,
COPY_MODE_SET_COLOR_8BIT,
COPY_MODE_MIPMAP,
COPY_MODE_LINEARIZE_DEPTH,
COPY_MODE_CUBE_TO_PANORAMA,
COPY_MODE_CUBE_ARRAY_TO_PANORAMA,
COPY_MODE_MAX,
};
enum {
COPY_FLAG_HORIZONTAL = (1 << 0),
COPY_FLAG_USE_COPY_SECTION = (1 << 1),
COPY_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 2),
COPY_FLAG_DOF_NEAR_FIRST_TAP = (1 << 3),
COPY_FLAG_GLOW_FIRST_PASS = (1 << 4),
COPY_FLAG_FLIP_Y = (1 << 5),
COPY_FLAG_FORCE_LUMINANCE = (1 << 6),
COPY_FLAG_ALL_SOURCE = (1 << 7),
COPY_FLAG_ALPHA_TO_ONE = (1 << 8),
};
struct CopyPushConstant {
int32_t section[4];
int32_t target[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_scale;
// DOF.
float camera_z_far;
float camera_z_near;
uint32_t pad2[2];
//SET color
float set_color[4];
};
struct Copy {
CopyPushConstant push_constant;
CopyShaderRD shader;
RID shader_version;
RID pipelines[COPY_MODE_MAX];
} copy;
// Copy to FB shader
enum CopyToFBMode {
COPY_TO_FB_COPY,
COPY_TO_FB_COPY_PANORAMA_TO_DP,
COPY_TO_FB_COPY2,
COPY_TO_FB_SET_COLOR,
// These variants are disabled unless XR shaders are enabled.
// They should be listed last.
COPY_TO_FB_MULTIVIEW,
COPY_TO_FB_MULTIVIEW_WITH_DEPTH,
COPY_TO_FB_MAX,
};
enum CopyToFBFlags {
COPY_TO_FB_FLAG_FLIP_Y = (1 << 0),
COPY_TO_FB_FLAG_USE_SECTION = (1 << 1),
COPY_TO_FB_FLAG_FORCE_LUMINANCE = (1 << 2),
COPY_TO_FB_FLAG_ALPHA_TO_ZERO = (1 << 3),
COPY_TO_FB_FLAG_SRGB = (1 << 4),
COPY_TO_FB_FLAG_ALPHA_TO_ONE = (1 << 5),
COPY_TO_FB_FLAG_LINEAR = (1 << 6),
COPY_TO_FB_FLAG_NORMAL = (1 << 7),
COPY_TO_FB_FLAG_USE_SRC_SECTION = (1 << 8),
};
struct CopyToFbPushConstant {
float section[4];
float pixel_size[2];
float luminance_multiplier;
uint32_t flags;
float set_color[4];
};
struct CopyToFb {
CopyToFbPushConstant push_constant;
CopyToFbShaderRD shader;
RID shader_version;
PipelineCacheRD pipelines[COPY_TO_FB_MAX];
} copy_to_fb;
// Copy to DP
struct CopyToDPPushConstant {
float z_far;
float z_near;
float texel_size[2];
float screen_rect[4];
};
struct CopyToDP {
CubeToDpShaderRD shader;
RID shader_version;
PipelineCacheRD pipeline;
} cube_to_dp;
// Cubemap effects
struct CubemapDownsamplerPushConstant {
uint32_t face_size;
uint32_t face_id;
float pad[2];
};
struct CubemapDownsampler {
CubemapDownsamplerPushConstant push_constant;
CubemapDownsamplerShaderRD compute_shader;
CubemapDownsamplerRasterShaderRD raster_shader;
RID shader_version;
RID compute_pipeline;
PipelineCacheRD raster_pipeline;
} cubemap_downsampler;
enum CubemapFilterMode {
FILTER_MODE_HIGH_QUALITY,
FILTER_MODE_LOW_QUALITY,
FILTER_MODE_HIGH_QUALITY_ARRAY,
FILTER_MODE_LOW_QUALITY_ARRAY,
FILTER_MODE_MAX,
};
struct CubemapFilterRasterPushConstant {
uint32_t mip_level;
uint32_t face_id;
float pad[2];
};
struct CubemapFilter {
CubemapFilterShaderRD compute_shader;
CubemapFilterRasterShaderRD raster_shader;
RID shader_version;
RID compute_pipelines[FILTER_MODE_MAX];
PipelineCacheRD raster_pipelines[FILTER_MODE_MAX];
RID uniform_set;
RID image_uniform_set;
RID coefficient_buffer;
bool use_high_quality;
} filter;
struct CubemapRoughnessPushConstant {
uint32_t face_id;
uint32_t sample_count;
float roughness;
uint32_t use_direct_write;
float face_size;
float pad[3];
};
struct CubemapRoughness {
CubemapRoughnessPushConstant push_constant;
CubemapRoughnessShaderRD compute_shader;
CubemapRoughnessRasterShaderRD raster_shader;
RID shader_version;
RID compute_pipeline;
PipelineCacheRD raster_pipeline;
} roughness;
// Merge specular
enum SpecularMergeMode {
SPECULAR_MERGE_ADD,
SPECULAR_MERGE_SSR,
SPECULAR_MERGE_ADDITIVE_ADD,
SPECULAR_MERGE_ADDITIVE_SSR,
SPECULAR_MERGE_ADD_MULTIVIEW,
SPECULAR_MERGE_SSR_MULTIVIEW,
SPECULAR_MERGE_ADDITIVE_ADD_MULTIVIEW,
SPECULAR_MERGE_ADDITIVE_SSR_MULTIVIEW,
SPECULAR_MERGE_MAX
};
/* Specular merge must be done using raster, rather than compute
* because it must continue the existing color buffer
*/
struct SpecularMerge {
SpecularMergeShaderRD shader;
RID shader_version;
PipelineCacheRD pipelines[SPECULAR_MERGE_MAX];
} specular_merge;
static CopyEffects *singleton;
public:
static CopyEffects *get_singleton();
CopyEffects(bool p_prefer_raster_effects);
~CopyEffects();
bool get_prefer_raster_effects() { return prefer_raster_effects; }
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);
void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false);
void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far);
void 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(), bool p_multiview = false, bool alpha_to_one = false, bool p_linear = false, bool p_normal = false, const Rect2 &p_src_rect = Rect2());
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 copy_to_drawlist(RD::DrawListID p_draw_list, RD::FramebufferFormatID p_fb_format, RID p_source_rd_texture, bool p_linear = false);
void copy_raster(RID p_source_texture, RID p_dest_framebuffer);
void gaussian_blur(RID p_source_rd_texture, RID p_texture, const Rect2i &p_region, const Size2i &p_size, bool p_8bit_dst = false);
void gaussian_blur_raster(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_region, const Size2i &p_size);
void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_threshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_scale = 1.0);
void gaussian_glow_raster(RID p_source_rd_texture, RID p_half_texture, RID p_dest_texture, float p_luminance_multiplier, const Size2i &p_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_threshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_scale = 1.0);
void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size);
void make_mipmap_raster(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size);
void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false);
void set_color_raster(RID p_dest_texture, const Color &p_color, const Rect2i &p_region);
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 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 cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level);
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 merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection, uint32_t p_view_count);
};
} // namespace RendererRD
#endif // COPY_EFFECTS_RD_H

View file

@ -0,0 +1,379 @@
/**************************************************************************/
/* debug_effects.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "debug_effects.h"
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/light_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
using namespace RendererRD;
DebugEffects::DebugEffects() {
{
// Shadow Frustum debug shader
Vector<String> modes;
modes.push_back("");
shadow_frustum.shader.initialize(modes);
shadow_frustum.shader_version = shadow_frustum.shader.version_create();
RD::PipelineRasterizationState raster_state = RD::PipelineRasterizationState();
shadow_frustum.pipelines[SFP_TRANSPARENT].setup(shadow_frustum.shader.version_get_shader(shadow_frustum.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, raster_state, RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0);
raster_state.wireframe = true;
shadow_frustum.pipelines[SFP_WIREFRAME].setup(shadow_frustum.shader.version_get_shader(shadow_frustum.shader_version, 0), RD::RENDER_PRIMITIVE_LINES, raster_state, RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
}
{
// Motion Vectors debug shader.
Vector<String> modes;
modes.push_back("");
motion_vectors.shader.initialize(modes);
motion_vectors.shader_version = motion_vectors.shader.version_create();
motion_vectors.pipeline.setup(motion_vectors.shader.version_get_shader(motion_vectors.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0);
}
}
void DebugEffects::_create_frustum_arrays() {
if (frustum.vertex_buffer.is_null()) {
// Create vertex buffer, but don't put data in it yet
frustum.vertex_buffer = RD::get_singleton()->vertex_buffer_create(8 * sizeof(float) * 3, Vector<uint8_t>(), false);
Vector<RD::VertexAttribute> attributes;
Vector<RID> buffers;
RD::VertexAttribute vd;
vd.location = 0;
vd.stride = sizeof(float) * 3;
vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
attributes.push_back(vd);
buffers.push_back(frustum.vertex_buffer);
frustum.vertex_format = RD::get_singleton()->vertex_format_create(attributes);
frustum.vertex_array = RD::get_singleton()->vertex_array_create(8, frustum.vertex_format, buffers);
}
if (frustum.index_buffer.is_null()) {
uint16_t indices[6 * 2 * 3] = {
// Far
0, 1, 2, // FLT, FLB, FRT
1, 3, 2, // FLB, FRB, FRT
// Near
4, 6, 5, // NLT, NRT, NLB
6, 7, 5, // NRT, NRB, NLB
// Left
0, 4, 1, // FLT, NLT, FLB
4, 5, 1, // NLT, NLB, FLB
// Right
6, 2, 7, // NRT, FRT, NRB
2, 3, 7, // FRT, FRB, NRB
// Top
0, 2, 4, // FLT, FRT, NLT
2, 6, 4, // FRT, NRT, NLT
// Bottom
5, 7, 1, // NLB, NRB, FLB,
7, 3, 1, // NRB, FRB, FLB
};
// Create our index_array
PackedByteArray data;
data.resize(6 * 2 * 3 * 2);
{
uint8_t *w = data.ptrw();
uint16_t *p16 = (uint16_t *)w;
for (int i = 0; i < 6 * 2 * 3; i++) {
*p16 = indices[i];
p16++;
}
}
frustum.index_buffer = RD::get_singleton()->index_buffer_create(6 * 2 * 3, RenderingDevice::INDEX_BUFFER_FORMAT_UINT16, data);
frustum.index_array = RD::get_singleton()->index_array_create(frustum.index_buffer, 0, 6 * 2 * 3);
}
if (frustum.lines_buffer.is_null()) {
uint16_t indices[12 * 2] = {
0, 1, // FLT - FLB
1, 3, // FLB - FRB
3, 2, // FRB - FRT
2, 0, // FRT - FLT
4, 6, // NLT - NRT
6, 7, // NRT - NRB
7, 5, // NRB - NLB
5, 4, // NLB - NLT
0, 4, // FLT - NLT
1, 5, // FLB - NLB
2, 6, // FRT - NRT
3, 7, // FRB - NRB
};
// Create our lines_array
PackedByteArray data;
data.resize(12 * 2 * 2);
{
uint8_t *w = data.ptrw();
uint16_t *p16 = (uint16_t *)w;
for (int i = 0; i < 12 * 2; i++) {
*p16 = indices[i];
p16++;
}
}
frustum.lines_buffer = RD::get_singleton()->index_buffer_create(12 * 2, RenderingDevice::INDEX_BUFFER_FORMAT_UINT16, data);
frustum.lines_array = RD::get_singleton()->index_array_create(frustum.lines_buffer, 0, 12 * 2);
}
}
DebugEffects::~DebugEffects() {
shadow_frustum.shader.version_free(shadow_frustum.shader_version);
// Destroy vertex buffer and array.
if (frustum.vertex_buffer.is_valid()) {
RD::get_singleton()->free(frustum.vertex_buffer); // Array gets freed as dependency.
}
// Destroy index buffer and array,
if (frustum.index_buffer.is_valid()) {
RD::get_singleton()->free(frustum.index_buffer); // Array gets freed as dependency.
}
// Destroy lines buffer and array.
if (frustum.lines_buffer.is_valid()) {
RD::get_singleton()->free(frustum.lines_buffer); // Array gets freed as dependency.
}
motion_vectors.shader.version_free(motion_vectors.shader_version);
}
void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_projection, const Transform3D &p_cam_transform, RID p_dest_fb, const Rect2 p_rect) {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
RID base = light_storage->light_instance_get_base_light(p_light);
ERR_FAIL_COND(light_storage->light_get_type(base) != RS::LIGHT_DIRECTIONAL);
// Make sure our buffers and arrays exist.
_create_frustum_arrays();
// Setup a points buffer for our view frustum.
PackedByteArray points;
points.resize(8 * sizeof(float) * 3);
// Get info about our splits.
RS::LightDirectionalShadowMode shadow_mode = light_storage->light_directional_get_shadow_mode(base);
bool overlap = light_storage->light_directional_get_blend_splits(base);
int splits = 1;
if (shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
splits = 4;
} else if (shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
splits = 2;
}
// Setup our camera info (this is mostly a duplicate of the logic found in RendererSceneCull::_light_instance_setup_directional_shadow).
bool is_orthogonal = p_cam_projection.is_orthogonal();
real_t aspect = p_cam_projection.get_aspect();
real_t fov = 0.0;
Vector2 vp_he;
if (is_orthogonal) {
vp_he = p_cam_projection.get_viewport_half_extents();
} else {
fov = p_cam_projection.get_fov(); //this is actually yfov, because set aspect tries to keep it
}
real_t min_distance = p_cam_projection.get_z_near();
real_t max_distance = p_cam_projection.get_z_far();
real_t shadow_max = RSG::light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE);
if (shadow_max > 0 && !is_orthogonal) {
max_distance = MIN(shadow_max, max_distance);
}
// Make sure we've not got bad info coming in.
max_distance = MAX(max_distance, min_distance + 0.001);
min_distance = MIN(min_distance, max_distance);
real_t range = max_distance - min_distance;
real_t distances[5];
distances[0] = min_distance;
for (int i = 0; i < splits; i++) {
distances[i + 1] = min_distance + RSG::light_storage->light_get_param(base, RS::LightParam(RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i)) * range;
};
distances[splits] = max_distance;
Color colors[4] = {
Color(1.0, 0.0, 0.0, 0.1),
Color(0.0, 1.0, 0.0, 0.1),
Color(0.0, 0.0, 1.0, 0.1),
Color(1.0, 1.0, 0.0, 0.1),
};
for (int split = 0; split < splits; split++) {
// Load frustum points into vertex buffer.
uint8_t *w = points.ptrw();
Vector3 *vw = (Vector3 *)w;
Projection projection;
if (is_orthogonal) {
projection.set_orthogonal(vp_he.y * 2.0, aspect, distances[(split == 0 || !overlap) ? split : split - 1], distances[split + 1], false);
} else {
projection.set_perspective(fov, aspect, distances[(split == 0 || !overlap) ? split : split - 1], distances[split + 1], true);
}
bool res = projection.get_endpoints(p_cam_transform, vw);
ERR_CONTINUE(!res);
RD::get_singleton()->buffer_update(frustum.vertex_buffer, 0, 8 * sizeof(float) * 3, w);
// Get our light projection info.
Projection light_projection = light_storage->light_instance_get_shadow_camera(p_light, split);
Transform3D light_transform = light_storage->light_instance_get_shadow_transform(p_light, split);
Rect2 atlas_rect_norm = light_storage->light_instance_get_directional_shadow_atlas_rect(p_light, split);
if (!is_orthogonal) {
light_transform.orthogonalize();
}
// Setup our push constant.
ShadowFrustumPushConstant push_constant;
MaterialStorage::store_camera(light_projection * Projection(light_transform.inverse()), push_constant.mvp);
push_constant.color[0] = colors[split].r;
push_constant.color[1] = colors[split].g;
push_constant.color[2] = colors[split].b;
push_constant.color[3] = colors[split].a;
// Adjust our rect to our atlas position.
Rect2 rect = p_rect;
rect.position.x += atlas_rect_norm.position.x * rect.size.x;
rect.position.y += atlas_rect_norm.position.y * rect.size.y;
rect.size.x *= atlas_rect_norm.size.x;
rect.size.y *= atlas_rect_norm.size.y;
// And draw our frustum.
RD::FramebufferFormatID fb_format_id = RD::get_singleton()->framebuffer_get_format(p_dest_fb);
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, rect);
RID pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array);
RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.index_array);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
pipeline = shadow_frustum.pipelines[SFP_WIREFRAME].get_render_pipeline(frustum.vertex_format, fb_format_id);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array);
RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.lines_array);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
RD::get_singleton()->draw_list_end();
if (split < (splits - 1) && splits > 1) {
// Also draw it in the last split so we get a proper overview of the whole view frustum...
// Get our light projection info.
light_projection = light_storage->light_instance_get_shadow_camera(p_light, (splits - 1));
light_transform = light_storage->light_instance_get_shadow_transform(p_light, (splits - 1));
atlas_rect_norm = light_storage->light_instance_get_directional_shadow_atlas_rect(p_light, (splits - 1));
if (!is_orthogonal) {
light_transform.orthogonalize();
}
// Update our push constant.
MaterialStorage::store_camera(light_projection * Projection(light_transform.inverse()), push_constant.mvp);
push_constant.color[0] = colors[split].r;
push_constant.color[1] = colors[split].g;
push_constant.color[2] = colors[split].b;
push_constant.color[3] = colors[split].a;
// Adjust our rect to our atlas position.
rect = p_rect;
rect.position.x += atlas_rect_norm.position.x * rect.size.x;
rect.position.y += atlas_rect_norm.position.y * rect.size.y;
rect.size.x *= atlas_rect_norm.size.x;
rect.size.y *= atlas_rect_norm.size.y;
draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, rect);
pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array);
RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.index_array);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
RD::get_singleton()->draw_list_end();
}
}
}
void DebugEffects::draw_motion_vectors(RID p_velocity, RID p_depth, RID p_dest_fb, const Projection &p_current_projection, const Transform3D &p_current_transform, const Projection &p_previous_projection, const Transform3D &p_previous_transform, Size2i p_resolution) {
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RD::Uniform u_source_velocity(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_velocity }));
RD::Uniform u_source_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, Vector<RID>({ default_sampler, p_depth }));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, motion_vectors.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_fb), false, RD::get_singleton()->draw_list_get_current_pass()));
Projection correction;
correction.set_depth_correction(true, true, false);
Projection reprojection = (correction * p_previous_projection) * p_previous_transform.affine_inverse() * p_current_transform * (correction * p_current_projection).inverse();
RendererRD::MaterialStorage::store_camera(reprojection, motion_vectors.push_constant.reprojection_matrix);
motion_vectors.push_constant.resolution[0] = p_resolution.width;
motion_vectors.push_constant.resolution[1] = p_resolution.height;
motion_vectors.push_constant.force_derive_from_depth = false;
RID shader = motion_vectors.shader.version_get_shader(motion_vectors.shader_version, 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_velocity, u_source_depth), 0);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &motion_vectors.push_constant, sizeof(MotionVectorsPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
#ifdef DRAW_DERIVATION_FROM_DEPTH_ON_TOP
motion_vectors.push_constant.force_derive_from_depth = true;
RD::get_singleton()->draw_list_set_push_constant(draw_list, &motion_vectors.push_constant, sizeof(MotionVectorsPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
#endif
RD::get_singleton()->draw_list_end();
}

View file

@ -0,0 +1,101 @@
/**************************************************************************/
/* debug_effects.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 DEBUG_EFFECTS_RD_H
#define DEBUG_EFFECTS_RD_H
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/motion_vectors.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/shadow_frustum.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
namespace RendererRD {
class DebugEffects {
private:
struct {
RD::VertexFormatID vertex_format;
RID vertex_buffer;
RID vertex_array;
RID index_buffer;
RID index_array;
RID lines_buffer;
RID lines_array;
} frustum;
struct ShadowFrustumPushConstant {
float mvp[16];
float color[4];
};
enum ShadowFrustumPipelines {
SFP_TRANSPARENT,
SFP_WIREFRAME,
SFP_MAX
};
struct {
ShadowFrustumShaderRD shader;
RID shader_version;
PipelineCacheRD pipelines[SFP_MAX];
} shadow_frustum;
struct MotionVectorsPushConstant {
float reprojection_matrix[16];
float resolution[2];
uint32_t force_derive_from_depth;
float pad;
};
struct {
MotionVectorsShaderRD shader;
RID shader_version;
PipelineCacheRD pipeline;
MotionVectorsPushConstant push_constant;
} motion_vectors;
void _create_frustum_arrays();
protected:
public:
DebugEffects();
~DebugEffects();
void draw_shadow_frustum(RID p_light, const Projection &p_cam_projection, const Transform3D &p_cam_transform, RID p_dest_fb, const Rect2 p_rect);
void draw_motion_vectors(RID p_velocity, RID p_depth, RID p_dest_fb, const Projection &p_current_projection, const Transform3D &p_current_transform, const Projection &p_previous_projection, const Transform3D &p_previous_transform, Size2i p_resolution);
};
} // namespace RendererRD
#endif // DEBUG_EFFECTS_RD_H

View file

@ -0,0 +1,128 @@
/**************************************************************************/
/* fsr.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "fsr.h"
#include "../storage_rd/material_storage.h"
#include "../uniform_set_cache_rd.h"
using namespace RendererRD;
FSR::FSR() {
Vector<String> FSR_upscale_modes;
#if defined(MACOS_ENABLED) || defined(IOS_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()->has_feature(RD::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_shader.initialize(FSR_upscale_modes);
shader_version = fsr_shader.version_create();
pipeline = RD::get_singleton()->compute_pipeline_create(fsr_shader.version_get_shader(shader_version, 0));
}
FSR::~FSR() {
fsr_shader.version_free(shader_version);
}
void FSR::fsr_upscale(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_rd_texture, RID p_destination_texture) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
Size2i internal_size = p_render_buffers->get_internal_size();
Size2i target_size = p_render_buffers->get_target_size();
float fsr_upscale_sharpness = p_render_buffers->get_fsr_sharpness();
if (!p_render_buffers->has_texture(SNAME("FSR"), SNAME("upscale_texture"))) {
RD::DataFormat format = p_render_buffers->get_base_data_format();
uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
uint32_t layers = 1; // we only need one layer, in multiview we're processing one layer at a time.
p_render_buffers->create_texture(SNAME("FSR"), SNAME("upscale_texture"), format, usage_bits, RD::TEXTURE_SAMPLES_1, target_size, layers);
}
RID upscale_texture = p_render_buffers->get_texture(SNAME("FSR"), SNAME("upscale_texture"));
FSRUpscalePushConstant push_constant;
memset(&push_constant, 0, sizeof(FSRUpscalePushConstant));
int dispatch_x = (target_size.x + 15) / 16;
int dispatch_y = (target_size.y + 15) / 16;
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipeline);
push_constant.resolution_width = internal_size.width;
push_constant.resolution_height = internal_size.height;
push_constant.upscaled_width = target_size.width;
push_constant.upscaled_height = target_size.height;
push_constant.sharpness = fsr_upscale_sharpness;
RID shader = fsr_shader.version_get_shader(shader_version, 0);
ERR_FAIL_COND(shader.is_null());
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
//FSR Easc
RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, { default_sampler, p_source_rd_texture });
RD::Uniform u_upscale_texture(RD::UNIFORM_TYPE_IMAGE, 0, { upscale_texture });
push_constant.pass = FSR_UPSCALE_PASS_EASU;
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_upscale_texture), 1);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &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
RD::Uniform u_upscale_texture_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, { default_sampler, upscale_texture });
RD::Uniform u_destination_texture(RD::UNIFORM_TYPE_IMAGE, 0, { p_destination_texture });
push_constant.pass = FSR_UPSCALE_PASS_RCAS;
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_upscale_texture_with_sampler), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_destination_texture), 1);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(FSRUpscalePushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1);
RD::get_singleton()->compute_list_end();
}

View file

@ -0,0 +1,72 @@
/**************************************************************************/
/* fsr.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 FSR_RD_H
#define FSR_RD_H
#include "../pipeline_cache_rd.h"
#include "../storage_rd/render_scene_buffers_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/fsr_upscale.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
namespace RendererRD {
class FSR {
public:
FSR();
~FSR();
void fsr_upscale(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_rd_texture, RID p_destination_texture);
private:
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;
};
FsrUpscaleShaderRD fsr_shader;
RID shader_version;
RID pipeline;
};
} // namespace RendererRD
#endif // FSR_RD_H

View file

@ -0,0 +1,887 @@
/**************************************************************************/
/* fsr2.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "fsr2.h"
#include "../storage_rd/material_storage.h"
#include "../uniform_set_cache_rd.h"
using namespace RendererRD;
#ifndef _MSC_VER
#include <wchar.h>
#define wcscpy_s wcscpy
#endif
static RD::TextureType ffx_resource_type_to_rd_texture_type(FfxResourceType p_type) {
switch (p_type) {
case FFX_RESOURCE_TYPE_TEXTURE1D:
return RD::TEXTURE_TYPE_1D;
case FFX_RESOURCE_TYPE_TEXTURE2D:
return RD::TEXTURE_TYPE_2D;
case FFX_RESOURCE_TYPE_TEXTURE3D:
return RD::TEXTURE_TYPE_3D;
default:
return RD::TEXTURE_TYPE_MAX;
}
}
static FfxResourceType rd_texture_type_to_ffx_resource_type(RD::TextureType p_type) {
switch (p_type) {
case RD::TEXTURE_TYPE_1D:
return FFX_RESOURCE_TYPE_TEXTURE1D;
case RD::TEXTURE_TYPE_2D:
return FFX_RESOURCE_TYPE_TEXTURE2D;
case RD::TEXTURE_TYPE_3D:
return FFX_RESOURCE_TYPE_TEXTURE3D;
default:
return FFX_RESOURCE_TYPE_BUFFER;
}
}
static RD::DataFormat ffx_surface_format_to_rd_format(FfxSurfaceFormat p_format) {
switch (p_format) {
case FFX_SURFACE_FORMAT_R32G32B32A32_TYPELESS:
return RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
case FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT:
return RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
case FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT:
return RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
case FFX_SURFACE_FORMAT_R16G16B16A16_UNORM:
return RD::DATA_FORMAT_R16G16B16A16_UNORM;
case FFX_SURFACE_FORMAT_R32G32_FLOAT:
return RD::DATA_FORMAT_R32G32_SFLOAT;
case FFX_SURFACE_FORMAT_R32_UINT:
return RD::DATA_FORMAT_R32_UINT;
case FFX_SURFACE_FORMAT_R8G8B8A8_TYPELESS:
return RD::DATA_FORMAT_R8G8B8A8_UNORM;
case FFX_SURFACE_FORMAT_R8G8B8A8_UNORM:
return RD::DATA_FORMAT_R8G8B8A8_UNORM;
case FFX_SURFACE_FORMAT_R11G11B10_FLOAT:
return RD::DATA_FORMAT_B10G11R11_UFLOAT_PACK32;
case FFX_SURFACE_FORMAT_R16G16_FLOAT:
return RD::DATA_FORMAT_R16G16_SFLOAT;
case FFX_SURFACE_FORMAT_R16G16_UINT:
return RD::DATA_FORMAT_R16G16_UINT;
case FFX_SURFACE_FORMAT_R16_FLOAT:
return RD::DATA_FORMAT_R16_SFLOAT;
case FFX_SURFACE_FORMAT_R16_UINT:
return RD::DATA_FORMAT_R16_UINT;
case FFX_SURFACE_FORMAT_R16_UNORM:
return RD::DATA_FORMAT_R16_UNORM;
case FFX_SURFACE_FORMAT_R16_SNORM:
return RD::DATA_FORMAT_R16_SNORM;
case FFX_SURFACE_FORMAT_R8_UNORM:
return RD::DATA_FORMAT_R8_UNORM;
case FFX_SURFACE_FORMAT_R8_UINT:
return RD::DATA_FORMAT_R8_UINT;
case FFX_SURFACE_FORMAT_R8G8_UNORM:
return RD::DATA_FORMAT_R8G8_UNORM;
case FFX_SURFACE_FORMAT_R32_FLOAT:
return RD::DATA_FORMAT_R32_SFLOAT;
default:
return RD::DATA_FORMAT_MAX;
}
}
static FfxSurfaceFormat rd_format_to_ffx_surface_format(RD::DataFormat p_format) {
switch (p_format) {
case RD::DATA_FORMAT_R32G32B32A32_SFLOAT:
return FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT;
case RD::DATA_FORMAT_R16G16B16A16_SFLOAT:
return FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT;
case RD::DATA_FORMAT_R16G16B16A16_UNORM:
return FFX_SURFACE_FORMAT_R16G16B16A16_UNORM;
case RD::DATA_FORMAT_R32G32_SFLOAT:
return FFX_SURFACE_FORMAT_R32G32_FLOAT;
case RD::DATA_FORMAT_R32_UINT:
return FFX_SURFACE_FORMAT_R32_UINT;
case RD::DATA_FORMAT_R8G8B8A8_UNORM:
return FFX_SURFACE_FORMAT_R8G8B8A8_UNORM;
case RD::DATA_FORMAT_B10G11R11_UFLOAT_PACK32:
return FFX_SURFACE_FORMAT_R11G11B10_FLOAT;
case RD::DATA_FORMAT_R16G16_SFLOAT:
return FFX_SURFACE_FORMAT_R16G16_FLOAT;
case RD::DATA_FORMAT_R16G16_UINT:
return FFX_SURFACE_FORMAT_R16G16_UINT;
case RD::DATA_FORMAT_R16_SFLOAT:
return FFX_SURFACE_FORMAT_R16_FLOAT;
case RD::DATA_FORMAT_R16_UINT:
return FFX_SURFACE_FORMAT_R16_UINT;
case RD::DATA_FORMAT_R16_UNORM:
return FFX_SURFACE_FORMAT_R16_UNORM;
case RD::DATA_FORMAT_R16_SNORM:
return FFX_SURFACE_FORMAT_R16_SNORM;
case RD::DATA_FORMAT_R8_UNORM:
return FFX_SURFACE_FORMAT_R8_UNORM;
case RD::DATA_FORMAT_R8_UINT:
return FFX_SURFACE_FORMAT_R8_UINT;
case RD::DATA_FORMAT_R8G8_UNORM:
return FFX_SURFACE_FORMAT_R8G8_UNORM;
case RD::DATA_FORMAT_R32_SFLOAT:
return FFX_SURFACE_FORMAT_R32_FLOAT;
default:
return FFX_SURFACE_FORMAT_UNKNOWN;
}
}
static uint32_t ffx_usage_to_rd_usage_flags(uint32_t p_flags) {
uint32_t ret = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
if (p_flags & FFX_RESOURCE_USAGE_RENDERTARGET) {
ret |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
}
if (p_flags & FFX_RESOURCE_USAGE_UAV) {
ret |= RD::TEXTURE_USAGE_STORAGE_BIT;
ret |= RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
ret |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
}
return ret;
}
static FfxErrorCode create_backend_context_rd(FfxFsr2Interface *p_backend_interface, FfxDevice p_device) {
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
// Store pointer to the device common to all contexts.
scratch.device = p_device;
// Create a ring buffer of uniform buffers.
// FIXME: This could be optimized to be a single memory block if it was possible for RD to create views into a particular memory range of a UBO.
for (uint32_t i = 0; i < FSR2_UBO_RING_BUFFER_SIZE; i++) {
scratch.ubo_ring_buffer[i] = RD::get_singleton()->uniform_buffer_create(FFX_MAX_CONST_SIZE * sizeof(uint32_t));
ERR_FAIL_COND_V(scratch.ubo_ring_buffer[i].is_null(), FFX_ERROR_BACKEND_API_ERROR);
}
return FFX_OK;
}
static FfxErrorCode get_device_capabilities_rd(FfxFsr2Interface *p_backend_interface, FfxDeviceCapabilities *p_out_device_capabilities, FfxDevice p_device) {
FSR2Effect::Device &effect_device = *reinterpret_cast<FSR2Effect::Device *>(p_device);
*p_out_device_capabilities = effect_device.capabilities;
return FFX_OK;
}
static FfxErrorCode destroy_backend_context_rd(FfxFsr2Interface *p_backend_interface) {
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
for (uint32_t i = 0; i < FSR2_UBO_RING_BUFFER_SIZE; i++) {
RD::get_singleton()->free(scratch.ubo_ring_buffer[i]);
}
return FFX_OK;
}
static FfxErrorCode create_resource_rd(FfxFsr2Interface *p_backend_interface, const FfxCreateResourceDescription *p_create_resource_description, FfxResourceInternal *p_out_resource) {
// FSR2's base implementation won't issue a call to create a heap type that isn't just default on its own,
// so we can safely ignore it as RD does not expose this concept.
ERR_FAIL_COND_V(p_create_resource_description->heapType != FFX_HEAP_TYPE_DEFAULT, FFX_ERROR_INVALID_ARGUMENT);
RenderingDevice *rd = RD::get_singleton();
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
FfxResourceDescription res_desc = p_create_resource_description->resourceDescription;
// FSR2's base implementation never requests buffer creation.
ERR_FAIL_COND_V(res_desc.type != FFX_RESOURCE_TYPE_TEXTURE1D && res_desc.type != FFX_RESOURCE_TYPE_TEXTURE2D && res_desc.type != FFX_RESOURCE_TYPE_TEXTURE3D, FFX_ERROR_INVALID_ARGUMENT);
if (res_desc.mipCount == 0) {
// Mipmap count must be derived from the resource's dimensions.
res_desc.mipCount = uint32_t(1 + floor(log2(MAX(MAX(res_desc.width, res_desc.height), res_desc.depth))));
}
Vector<PackedByteArray> initial_data;
if (p_create_resource_description->initDataSize) {
PackedByteArray byte_array;
byte_array.resize(p_create_resource_description->initDataSize);
memcpy(byte_array.ptrw(), p_create_resource_description->initData, p_create_resource_description->initDataSize);
initial_data.push_back(byte_array);
}
RD::TextureFormat texture_format;
texture_format.texture_type = ffx_resource_type_to_rd_texture_type(res_desc.type);
texture_format.format = ffx_surface_format_to_rd_format(res_desc.format);
texture_format.usage_bits = ffx_usage_to_rd_usage_flags(p_create_resource_description->usage);
texture_format.width = res_desc.width;
texture_format.height = res_desc.height;
texture_format.depth = res_desc.depth;
texture_format.mipmaps = res_desc.mipCount;
RID texture = rd->texture_create(texture_format, RD::TextureView(), initial_data);
ERR_FAIL_COND_V(texture.is_null(), FFX_ERROR_BACKEND_API_ERROR);
rd->set_resource_name(texture, String(p_create_resource_description->name));
// Add the resource to the storage and use the internal index to reference it.
p_out_resource->internalIndex = scratch.resources.add(texture, false, p_create_resource_description->id, res_desc);
return FFX_OK;
}
static FfxErrorCode register_resource_rd(FfxFsr2Interface *p_backend_interface, const FfxResource *p_in_resource, FfxResourceInternal *p_out_resource) {
if (p_in_resource->resource == nullptr) {
// Null resource case.
p_out_resource->internalIndex = -1;
return FFX_OK;
}
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
const RID &rid = *reinterpret_cast<const RID *>(p_in_resource->resource);
ERR_FAIL_COND_V(rid.is_null(), FFX_ERROR_INVALID_ARGUMENT);
// Add the resource to the storage and use the internal index to reference it.
p_out_resource->internalIndex = scratch.resources.add(rid, true, FSR2Context::RESOURCE_ID_DYNAMIC, p_in_resource->description);
return FFX_OK;
}
static FfxErrorCode unregister_resources_rd(FfxFsr2Interface *p_backend_interface) {
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
LocalVector<uint32_t> dynamic_list_copy = scratch.resources.dynamic_list;
for (uint32_t i : dynamic_list_copy) {
scratch.resources.remove(i);
}
return FFX_OK;
}
static FfxResourceDescription get_resource_description_rd(FfxFsr2Interface *p_backend_interface, FfxResourceInternal p_resource) {
if (p_resource.internalIndex != -1) {
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
return scratch.resources.descriptions[p_resource.internalIndex];
} else {
return {};
}
}
static FfxErrorCode destroy_resource_rd(FfxFsr2Interface *p_backend_interface, FfxResourceInternal p_resource) {
if (p_resource.internalIndex != -1) {
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
if (scratch.resources.rids[p_resource.internalIndex].is_valid()) {
RD::get_singleton()->free(scratch.resources.rids[p_resource.internalIndex]);
scratch.resources.remove(p_resource.internalIndex);
}
}
return FFX_OK;
}
static FfxErrorCode create_pipeline_rd(FfxFsr2Interface *p_backend_interface, FfxFsr2Pass p_pass, const FfxPipelineDescription *p_pipeline_description, FfxPipelineState *p_out_pipeline) {
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
FSR2Effect::Device &device = *reinterpret_cast<FSR2Effect::Device *>(scratch.device);
FSR2Effect::Pass &effect_pass = device.passes[p_pass];
if (effect_pass.pipeline.pipeline_rid.is_null()) {
// Create pipeline for the device if it hasn't been created yet.
effect_pass.root_signature.shader_rid = effect_pass.shader->version_get_shader(effect_pass.shader_version, effect_pass.shader_variant);
ERR_FAIL_COND_V(effect_pass.root_signature.shader_rid.is_null(), FFX_ERROR_BACKEND_API_ERROR);
effect_pass.pipeline.pipeline_rid = RD::get_singleton()->compute_pipeline_create(effect_pass.root_signature.shader_rid);
ERR_FAIL_COND_V(effect_pass.pipeline.pipeline_rid.is_null(), FFX_ERROR_BACKEND_API_ERROR);
}
// While this is not their intended use, we use the pipeline and root signature pointers to store the
// RIDs to the pipeline and shader that RD needs for the compute pipeline.
p_out_pipeline->pipeline = reinterpret_cast<FfxPipeline>(&effect_pass.pipeline);
p_out_pipeline->rootSignature = reinterpret_cast<FfxRootSignature>(&effect_pass.root_signature);
p_out_pipeline->srvCount = effect_pass.sampled_bindings.size();
ERR_FAIL_COND_V(p_out_pipeline->srvCount > FFX_MAX_NUM_SRVS, FFX_ERROR_OUT_OF_RANGE);
memcpy(p_out_pipeline->srvResourceBindings, effect_pass.sampled_bindings.ptr(), sizeof(FfxResourceBinding) * p_out_pipeline->srvCount);
p_out_pipeline->uavCount = effect_pass.storage_bindings.size();
ERR_FAIL_COND_V(p_out_pipeline->uavCount > FFX_MAX_NUM_UAVS, FFX_ERROR_OUT_OF_RANGE);
memcpy(p_out_pipeline->uavResourceBindings, effect_pass.storage_bindings.ptr(), sizeof(FfxResourceBinding) * p_out_pipeline->uavCount);
p_out_pipeline->constCount = effect_pass.uniform_bindings.size();
ERR_FAIL_COND_V(p_out_pipeline->constCount > FFX_MAX_NUM_CONST_BUFFERS, FFX_ERROR_OUT_OF_RANGE);
memcpy(p_out_pipeline->cbResourceBindings, effect_pass.uniform_bindings.ptr(), sizeof(FfxResourceBinding) * p_out_pipeline->constCount);
bool low_resolution_mvs = (p_pipeline_description->contextFlags & FFX_FSR2_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS) == 0;
if (p_pass == FFX_FSR2_PASS_ACCUMULATE || p_pass == FFX_FSR2_PASS_ACCUMULATE_SHARPEN) {
// Change the binding for motion vectors in this particular pass if low resolution MVs are used.
if (low_resolution_mvs) {
FfxResourceBinding &binding = p_out_pipeline->srvResourceBindings[2];
wcscpy_s(binding.name, L"r_dilated_motion_vectors");
}
}
return FFX_OK;
}
static FfxErrorCode destroy_pipeline_rd(FfxFsr2Interface *p_backend_interface, FfxPipelineState *p_pipeline) {
// We don't want to destroy pipelines when the FSR2 API deems it necessary as it'll do so whenever the context is destroyed.
return FFX_OK;
}
static FfxErrorCode schedule_gpu_job_rd(FfxFsr2Interface *p_backend_interface, const FfxGpuJobDescription *p_job) {
ERR_FAIL_NULL_V(p_backend_interface, FFX_ERROR_INVALID_ARGUMENT);
ERR_FAIL_NULL_V(p_job, FFX_ERROR_INVALID_ARGUMENT);
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
scratch.gpu_jobs.push_back(*p_job);
return FFX_OK;
}
static FfxErrorCode execute_gpu_job_clear_float_rd(FSR2Context::Scratch &p_scratch, const FfxClearFloatJobDescription &p_job) {
RID resource = p_scratch.resources.rids[p_job.target.internalIndex];
FfxResourceDescription &desc = p_scratch.resources.descriptions[p_job.target.internalIndex];
ERR_FAIL_COND_V(desc.type == FFX_RESOURCE_TYPE_BUFFER, FFX_ERROR_INVALID_ARGUMENT);
Color color(p_job.color[0], p_job.color[1], p_job.color[2], p_job.color[3]);
RD::get_singleton()->texture_clear(resource, color, 0, desc.mipCount, 0, 1);
return FFX_OK;
}
static FfxErrorCode execute_gpu_job_copy_rd(FSR2Context::Scratch &p_scratch, const FfxCopyJobDescription &p_job) {
RID src = p_scratch.resources.rids[p_job.src.internalIndex];
RID dst = p_scratch.resources.rids[p_job.dst.internalIndex];
FfxResourceDescription &src_desc = p_scratch.resources.descriptions[p_job.src.internalIndex];
FfxResourceDescription &dst_desc = p_scratch.resources.descriptions[p_job.dst.internalIndex];
ERR_FAIL_COND_V(src_desc.type == FFX_RESOURCE_TYPE_BUFFER, FFX_ERROR_INVALID_ARGUMENT);
ERR_FAIL_COND_V(dst_desc.type == FFX_RESOURCE_TYPE_BUFFER, FFX_ERROR_INVALID_ARGUMENT);
for (uint32_t mip_level = 0; mip_level < src_desc.mipCount; mip_level++) {
RD::get_singleton()->texture_copy(src, dst, Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(src_desc.width, src_desc.height, src_desc.depth), mip_level, mip_level, 0, 0);
}
return FFX_OK;
}
static FfxErrorCode execute_gpu_job_compute_rd(FSR2Context::Scratch &p_scratch, const FfxComputeJobDescription &p_job) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL_V(uniform_set_cache, FFX_ERROR_BACKEND_API_ERROR);
FSR2Effect::RootSignature &root_signature = *reinterpret_cast<FSR2Effect::RootSignature *>(p_job.pipeline.rootSignature);
ERR_FAIL_COND_V(root_signature.shader_rid.is_null(), FFX_ERROR_INVALID_ARGUMENT);
FSR2Effect::Pipeline &backend_pipeline = *reinterpret_cast<FSR2Effect::Pipeline *>(p_job.pipeline.pipeline);
ERR_FAIL_COND_V(backend_pipeline.pipeline_rid.is_null(), FFX_ERROR_INVALID_ARGUMENT);
Vector<RD::Uniform> compute_uniforms;
for (uint32_t i = 0; i < p_job.pipeline.srvCount; i++) {
RID texture_rid = p_scratch.resources.rids[p_job.srvs[i].internalIndex];
RD::Uniform texture_uniform(RD::UNIFORM_TYPE_TEXTURE, p_job.pipeline.srvResourceBindings[i].slotIndex, texture_rid);
compute_uniforms.push_back(texture_uniform);
}
for (uint32_t i = 0; i < p_job.pipeline.uavCount; i++) {
RID image_rid = p_scratch.resources.rids[p_job.uavs[i].internalIndex];
RD::Uniform storage_uniform;
storage_uniform.uniform_type = RD::UNIFORM_TYPE_IMAGE;
storage_uniform.binding = p_job.pipeline.uavResourceBindings[i].slotIndex;
if (p_job.uavMip[i] > 0) {
LocalVector<RID> &mip_slice_rids = p_scratch.resources.mip_slice_rids[p_job.uavs[i].internalIndex];
if (mip_slice_rids.is_empty()) {
mip_slice_rids.resize(p_scratch.resources.descriptions[p_job.uavs[i].internalIndex].mipCount);
}
ERR_FAIL_COND_V(p_job.uavMip[i] >= mip_slice_rids.size(), FFX_ERROR_INVALID_ARGUMENT);
if (mip_slice_rids[p_job.uavMip[i]].is_null()) {
mip_slice_rids[p_job.uavMip[i]] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), image_rid, 0, p_job.uavMip[i]);
}
ERR_FAIL_COND_V(mip_slice_rids[p_job.uavMip[i]].is_null(), FFX_ERROR_BACKEND_API_ERROR);
storage_uniform.append_id(mip_slice_rids[p_job.uavMip[i]]);
} else {
storage_uniform.append_id(image_rid);
}
compute_uniforms.push_back(storage_uniform);
}
for (uint32_t i = 0; i < p_job.pipeline.constCount; i++) {
RID buffer_rid = p_scratch.ubo_ring_buffer[p_scratch.ubo_ring_buffer_index];
p_scratch.ubo_ring_buffer_index = (p_scratch.ubo_ring_buffer_index + 1) % FSR2_UBO_RING_BUFFER_SIZE;
RD::get_singleton()->buffer_update(buffer_rid, 0, p_job.cbs[i].uint32Size * sizeof(uint32_t), p_job.cbs[i].data);
RD::Uniform buffer_uniform(RD::UNIFORM_TYPE_UNIFORM_BUFFER, p_job.pipeline.cbResourceBindings[i].slotIndex, buffer_rid);
compute_uniforms.push_back(buffer_uniform);
}
FSR2Effect::Device &device = *reinterpret_cast<FSR2Effect::Device *>(p_scratch.device);
RD::Uniform u_point_clamp_sampler(RD::UniformType::UNIFORM_TYPE_SAMPLER, 0, device.point_clamp_sampler);
RD::Uniform u_linear_clamp_sampler(RD::UniformType::UNIFORM_TYPE_SAMPLER, 1, device.linear_clamp_sampler);
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, backend_pipeline.pipeline_rid);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(root_signature.shader_rid, 0, u_point_clamp_sampler, u_linear_clamp_sampler), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache_vec(root_signature.shader_rid, 1, compute_uniforms), 1);
RD::get_singleton()->compute_list_dispatch(compute_list, p_job.dimensions[0], p_job.dimensions[1], p_job.dimensions[2]);
RD::get_singleton()->compute_list_end();
return FFX_OK;
}
static FfxErrorCode execute_gpu_jobs_rd(FfxFsr2Interface *p_backend_interface, FfxCommandList p_command_list) {
ERR_FAIL_NULL_V(p_backend_interface, FFX_ERROR_INVALID_ARGUMENT);
FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
FfxErrorCode error_code = FFX_OK;
for (const FfxGpuJobDescription &job : scratch.gpu_jobs) {
switch (job.jobType) {
case FFX_GPU_JOB_CLEAR_FLOAT: {
error_code = execute_gpu_job_clear_float_rd(scratch, job.clearJobDescriptor);
} break;
case FFX_GPU_JOB_COPY: {
error_code = execute_gpu_job_copy_rd(scratch, job.copyJobDescriptor);
} break;
case FFX_GPU_JOB_COMPUTE: {
error_code = execute_gpu_job_compute_rd(scratch, job.computeJobDescriptor);
} break;
default: {
error_code = FFX_ERROR_INVALID_ARGUMENT;
} break;
}
if (error_code != FFX_OK) {
scratch.gpu_jobs.clear();
return error_code;
}
}
scratch.gpu_jobs.clear();
return FFX_OK;
}
static FfxResource get_resource_rd(RID *p_rid, const wchar_t *p_name) {
FfxResource res = {};
if (p_rid->is_null()) {
return res;
}
wcscpy_s(res.name, p_name);
RD::TextureFormat texture_format = RD::get_singleton()->texture_get_format(*p_rid);
res.description.type = rd_texture_type_to_ffx_resource_type(texture_format.texture_type);
res.description.format = rd_format_to_ffx_surface_format(texture_format.format);
res.description.width = texture_format.width;
res.description.height = texture_format.height;
res.description.depth = texture_format.depth;
res.description.mipCount = texture_format.mipmaps;
res.description.flags = FFX_RESOURCE_FLAGS_NONE;
res.resource = reinterpret_cast<void *>(p_rid);
res.isDepth = texture_format.usage_bits & RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
return res;
}
FSR2Context::~FSR2Context() {
ffxFsr2ContextDestroy(&fsr_context);
}
FSR2Effect::FSR2Effect() {
FfxDeviceCapabilities &capabilities = device.capabilities;
uint64_t default_subgroup_size = RD::get_singleton()->limit_get(RD::LIMIT_SUBGROUP_SIZE);
capabilities.minimumSupportedShaderModel = FFX_SHADER_MODEL_5_1;
capabilities.waveLaneCountMin = RD::get_singleton()->limit_get(RD::LIMIT_SUBGROUP_MIN_SIZE);
capabilities.waveLaneCountMax = RD::get_singleton()->limit_get(RD::LIMIT_SUBGROUP_MAX_SIZE);
capabilities.fp16Supported = RD::get_singleton()->has_feature(RD::Features::SUPPORTS_FSR_HALF_FLOAT);
capabilities.raytracingSupported = false;
bool force_wave_64 = default_subgroup_size == 32 && capabilities.waveLaneCountMax == 64;
bool use_lut = force_wave_64 || default_subgroup_size == 64;
String general_defines_base =
"\n#define FFX_GPU\n"
"\n#define FFX_GLSL 1\n"
"\n#define FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS 1\n"
"\n#define FFX_FSR2_OPTION_HDR_COLOR_INPUT 1\n"
"\n#define FFX_FSR2_OPTION_INVERTED_DEPTH 1\n"
"\n#define FFX_FSR2_OPTION_GODOT_REACTIVE_MASK_CLAMP 1\n"
"\n#define FFX_FSR2_OPTION_GODOT_DERIVE_INVALID_MOTION_VECTORS 1\n";
if (use_lut) {
general_defines_base += "\n#define FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE 1\n";
}
String general_defines = general_defines_base;
if (capabilities.fp16Supported) {
general_defines += "\n#define FFX_HALF 1\n";
}
Vector<String> modes;
modes.push_back("");
// Since Godot currently lacks a shader reflection mechanism to persist the name of the bindings in the shader cache and
// there's also no mechanism to compile the shaders offline, the bindings are created manually by looking at the GLSL
// files included in FSR2 and mapping the macro bindings (#define FSR2_BIND_*) to their respective implementation names.
//
// It is not guaranteed these will remain consistent at all between versions of FSR2, so it'll be necessary to keep these
// bindings up to date whenever the library is updated. In such cases, it is very likely the validation layer will throw an
// error if the bindings do not match.
{
Pass &pass = device.passes[FFX_FSR2_PASS_DEPTH_CLIP];
pass.shader = &shaders.depth_clip;
pass.shader->initialize(modes, general_defines);
pass.shader_version = pass.shader->version_create();
pass.sampled_bindings = {
FfxResourceBinding{ 0, 0, L"r_reconstructed_previous_nearest_depth" },
FfxResourceBinding{ 1, 0, L"r_dilated_motion_vectors" },
FfxResourceBinding{ 2, 0, L"r_dilatedDepth" },
FfxResourceBinding{ 3, 0, L"r_reactive_mask" },
FfxResourceBinding{ 4, 0, L"r_transparency_and_composition_mask" },
FfxResourceBinding{ 6, 0, L"r_previous_dilated_motion_vectors" },
FfxResourceBinding{ 7, 0, L"r_input_motion_vectors" },
FfxResourceBinding{ 8, 0, L"r_input_color_jittered" },
FfxResourceBinding{ 9, 0, L"r_input_depth" },
FfxResourceBinding{ 10, 0, L"r_input_exposure" }
};
pass.storage_bindings = {
// FSR2_BIND_UAV_DEPTH_CLIP (11) does not point to anything.
FfxResourceBinding{ 12, 0, L"rw_dilated_reactive_masks" },
FfxResourceBinding{ 13, 0, L"rw_prepared_input_color" }
};
pass.uniform_bindings = {
FfxResourceBinding{ 14, 0, L"cbFSR2" }
};
}
{
Pass &pass = device.passes[FFX_FSR2_PASS_RECONSTRUCT_PREVIOUS_DEPTH];
pass.shader = &shaders.reconstruct_previous_depth;
pass.shader->initialize(modes, general_defines);
pass.shader_version = pass.shader->version_create();
pass.sampled_bindings = {
FfxResourceBinding{ 0, 0, L"r_input_motion_vectors" },
FfxResourceBinding{ 1, 0, L"r_input_depth" },
FfxResourceBinding{ 2, 0, L"r_input_color_jittered" },
FfxResourceBinding{ 3, 0, L"r_input_exposure" },
FfxResourceBinding{ 4, 0, L"r_luma_history" }
};
pass.storage_bindings = {
FfxResourceBinding{ 5, 0, L"rw_reconstructed_previous_nearest_depth" },
FfxResourceBinding{ 6, 0, L"rw_dilated_motion_vectors" },
FfxResourceBinding{ 7, 0, L"rw_dilatedDepth" },
FfxResourceBinding{ 8, 0, L"rw_prepared_input_color" },
FfxResourceBinding{ 9, 0, L"rw_luma_history" },
// FSR2_BIND_UAV_LUMA_INSTABILITY (10) does not point to anything.
FfxResourceBinding{ 11, 0, L"rw_lock_input_luma" }
};
pass.uniform_bindings = {
FfxResourceBinding{ 12, 0, L"cbFSR2" }
};
}
{
Pass &pass = device.passes[FFX_FSR2_PASS_LOCK];
pass.shader = &shaders.lock;
pass.shader->initialize(modes, general_defines);
pass.shader_version = pass.shader->version_create();
pass.sampled_bindings = {
FfxResourceBinding{ 0, 0, L"r_lock_input_luma" }
};
pass.storage_bindings = {
FfxResourceBinding{ 1, 0, L"rw_new_locks" },
FfxResourceBinding{ 2, 0, L"rw_reconstructed_previous_nearest_depth" }
};
pass.uniform_bindings = {
FfxResourceBinding{ 3, 0, L"cbFSR2" }
};
}
{
Vector<String> accumulate_modes;
accumulate_modes.push_back("\n");
accumulate_modes.push_back("\n#define FFX_FSR2_OPTION_APPLY_SHARPENING 1\n");
String general_defines_accumulate;
if (RD::get_singleton()->get_device_vendor_name() == "NVIDIA") {
// Workaround: Disable FP16 path for the accumulate pass on NVIDIA due to reduced occupancy and high VRAM throughput.
general_defines_accumulate = general_defines_base;
} else {
general_defines_accumulate = general_defines;
}
Pass &pass = device.passes[FFX_FSR2_PASS_ACCUMULATE];
pass.shader = &shaders.accumulate;
pass.shader->initialize(accumulate_modes, general_defines_accumulate);
pass.shader_version = pass.shader->version_create();
pass.sampled_bindings = {
FfxResourceBinding{ 0, 0, L"r_input_exposure" },
FfxResourceBinding{ 1, 0, L"r_dilated_reactive_masks" },
FfxResourceBinding{ 2, 0, L"r_input_motion_vectors" },
FfxResourceBinding{ 3, 0, L"r_internal_upscaled_color" },
FfxResourceBinding{ 4, 0, L"r_lock_status" },
FfxResourceBinding{ 5, 0, L"r_input_depth" },
FfxResourceBinding{ 6, 0, L"r_prepared_input_color" },
// FSR2_BIND_SRV_LUMA_INSTABILITY(7) does not point to anything.
FfxResourceBinding{ 8, 0, L"r_lanczos_lut" },
FfxResourceBinding{ 9, 0, L"r_upsample_maximum_bias_lut" },
FfxResourceBinding{ 10, 0, L"r_imgMips" },
FfxResourceBinding{ 11, 0, L"r_auto_exposure" },
FfxResourceBinding{ 12, 0, L"r_luma_history" }
};
pass.storage_bindings = {
FfxResourceBinding{ 13, 0, L"rw_internal_upscaled_color" },
FfxResourceBinding{ 14, 0, L"rw_lock_status" },
FfxResourceBinding{ 15, 0, L"rw_upscaled_output" },
FfxResourceBinding{ 16, 0, L"rw_new_locks" },
FfxResourceBinding{ 17, 0, L"rw_luma_history" }
};
pass.uniform_bindings = {
FfxResourceBinding{ 18, 0, L"cbFSR2" }
};
// Sharpen pass is a clone of the accumulate pass.
Pass &sharpen_pass = device.passes[FFX_FSR2_PASS_ACCUMULATE_SHARPEN];
sharpen_pass = pass;
sharpen_pass.shader_variant = 1;
}
{
Pass &pass = device.passes[FFX_FSR2_PASS_RCAS];
pass.shader = &shaders.rcas;
pass.shader->initialize(modes, general_defines_base);
pass.shader_version = pass.shader->version_create();
pass.sampled_bindings = {
FfxResourceBinding{ 0, 0, L"r_input_exposure" },
FfxResourceBinding{ 1, 0, L"r_rcas_input" }
};
pass.storage_bindings = {
FfxResourceBinding{ 2, 0, L"rw_upscaled_output" }
};
pass.uniform_bindings = {
FfxResourceBinding{ 3, 0, L"cbFSR2" },
FfxResourceBinding{ 4, 0, L"cbRCAS" }
};
}
{
Pass &pass = device.passes[FFX_FSR2_PASS_COMPUTE_LUMINANCE_PYRAMID];
pass.shader = &shaders.compute_luminance_pyramid;
pass.shader->initialize(modes, general_defines_base);
pass.shader_version = pass.shader->version_create();
pass.sampled_bindings = {
FfxResourceBinding{ 0, 0, L"r_input_color_jittered" }
};
pass.storage_bindings = {
FfxResourceBinding{ 1, 0, L"rw_spd_global_atomic" },
FfxResourceBinding{ 2, 0, L"rw_img_mip_shading_change" },
FfxResourceBinding{ 3, 0, L"rw_img_mip_5" },
FfxResourceBinding{ 4, 0, L"rw_auto_exposure" }
};
pass.uniform_bindings = {
FfxResourceBinding{ 5, 0, L"cbFSR2" },
FfxResourceBinding{ 6, 0, L"cbSPD" }
};
}
{
Pass &pass = device.passes[FFX_FSR2_PASS_GENERATE_REACTIVE];
pass.shader = &shaders.autogen_reactive;
pass.shader->initialize(modes, general_defines);
pass.shader_version = pass.shader->version_create();
pass.sampled_bindings = {
FfxResourceBinding{ 0, 0, L"r_input_opaque_only" },
FfxResourceBinding{ 1, 0, L"r_input_color_jittered" }
};
pass.storage_bindings = {
FfxResourceBinding{ 2, 0, L"rw_output_autoreactive" }
};
pass.uniform_bindings = {
FfxResourceBinding{ 3, 0, L"cbGenerateReactive" },
FfxResourceBinding{ 4, 0, L"cbFSR2" }
};
}
{
Pass &pass = device.passes[FFX_FSR2_PASS_TCR_AUTOGENERATE];
pass.shader = &shaders.tcr_autogen;
pass.shader->initialize(modes, general_defines);
pass.shader_version = pass.shader->version_create();
pass.sampled_bindings = {
FfxResourceBinding{ 0, 0, L"r_input_opaque_only" },
FfxResourceBinding{ 1, 0, L"r_input_color_jittered" },
FfxResourceBinding{ 2, 0, L"r_input_motion_vectors" },
FfxResourceBinding{ 3, 0, L"r_input_prev_color_pre_alpha" },
FfxResourceBinding{ 4, 0, L"r_input_prev_color_post_alpha" },
FfxResourceBinding{ 5, 0, L"r_reactive_mask" },
FfxResourceBinding{ 6, 0, L"r_transparency_and_composition_mask" },
FfxResourceBinding{ 13, 0, L"r_input_depth" }
};
pass.storage_bindings = {
FfxResourceBinding{ 7, 0, L"rw_output_autoreactive" },
FfxResourceBinding{ 8, 0, L"rw_output_autocomposition" },
FfxResourceBinding{ 9, 0, L"rw_output_prev_color_pre_alpha" },
FfxResourceBinding{ 10, 0, L"rw_output_prev_color_post_alpha" }
};
pass.uniform_bindings = {
FfxResourceBinding{ 11, 0, L"cbFSR2" },
FfxResourceBinding{ 12, 0, L"cbGenerateReactive" }
};
}
RD::SamplerState state;
state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
state.min_filter = RD::SAMPLER_FILTER_NEAREST;
state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
state.repeat_w = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
state.min_lod = -1000.0f;
state.max_lod = 1000.0f;
state.anisotropy_max = 1.0;
device.point_clamp_sampler = RD::get_singleton()->sampler_create(state);
ERR_FAIL_COND(device.point_clamp_sampler.is_null());
state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
state.min_filter = RD::SAMPLER_FILTER_LINEAR;
device.linear_clamp_sampler = RD::get_singleton()->sampler_create(state);
ERR_FAIL_COND(device.linear_clamp_sampler.is_null());
}
FSR2Effect::~FSR2Effect() {
RD::get_singleton()->free(device.point_clamp_sampler);
RD::get_singleton()->free(device.linear_clamp_sampler);
for (uint32_t i = 0; i < FFX_FSR2_PASS_COUNT; i++) {
if (device.passes[i].pipeline.pipeline_rid.is_valid()) {
RD::get_singleton()->free(device.passes[i].pipeline.pipeline_rid);
}
device.passes[i].shader->version_free(device.passes[i].shader_version);
}
}
FSR2Context *FSR2Effect::create_context(Size2i p_internal_size, Size2i p_target_size) {
FSR2Context *context = memnew(RendererRD::FSR2Context);
context->fsr_desc.flags = FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE | FFX_FSR2_ENABLE_DEPTH_INVERTED;
context->fsr_desc.maxRenderSize.width = p_internal_size.x;
context->fsr_desc.maxRenderSize.height = p_internal_size.y;
context->fsr_desc.displaySize.width = p_target_size.x;
context->fsr_desc.displaySize.height = p_target_size.y;
context->fsr_desc.device = &device;
FfxFsr2Interface &functions = context->fsr_desc.callbacks;
functions.fpCreateBackendContext = create_backend_context_rd;
functions.fpGetDeviceCapabilities = get_device_capabilities_rd;
functions.fpDestroyBackendContext = destroy_backend_context_rd;
functions.fpCreateResource = create_resource_rd;
functions.fpRegisterResource = register_resource_rd;
functions.fpUnregisterResources = unregister_resources_rd;
functions.fpGetResourceDescription = get_resource_description_rd;
functions.fpDestroyResource = destroy_resource_rd;
functions.fpCreatePipeline = create_pipeline_rd;
functions.fpDestroyPipeline = destroy_pipeline_rd;
functions.fpScheduleGpuJob = schedule_gpu_job_rd;
functions.fpExecuteGpuJobs = execute_gpu_jobs_rd;
functions.scratchBuffer = &context->scratch;
functions.scratchBufferSize = sizeof(context->scratch);
FfxErrorCode result = ffxFsr2ContextCreate(&context->fsr_context, &context->fsr_desc);
if (result == FFX_OK) {
return context;
} else {
memdelete(context);
return nullptr;
}
}
void FSR2Effect::upscale(const Parameters &p_params) {
// TODO: Transparency & Composition mask is not implemented.
FfxFsr2DispatchDescription dispatch_desc = {};
RID color = p_params.color;
RID depth = p_params.depth;
RID velocity = p_params.velocity;
RID reactive = p_params.reactive;
RID exposure = p_params.exposure;
RID output = p_params.output;
dispatch_desc.commandList = nullptr;
dispatch_desc.color = get_resource_rd(&color, L"color");
dispatch_desc.depth = get_resource_rd(&depth, L"depth");
dispatch_desc.motionVectors = get_resource_rd(&velocity, L"velocity");
dispatch_desc.reactive = get_resource_rd(&reactive, L"reactive");
dispatch_desc.exposure = get_resource_rd(&exposure, L"exposure");
dispatch_desc.transparencyAndComposition = {};
dispatch_desc.output = get_resource_rd(&output, L"output");
dispatch_desc.colorOpaqueOnly = {};
dispatch_desc.jitterOffset.x = p_params.jitter.x;
dispatch_desc.jitterOffset.y = p_params.jitter.y;
dispatch_desc.motionVectorScale.x = float(p_params.internal_size.width);
dispatch_desc.motionVectorScale.y = float(p_params.internal_size.height);
dispatch_desc.reset = p_params.reset_accumulation;
dispatch_desc.renderSize.width = p_params.internal_size.width;
dispatch_desc.renderSize.height = p_params.internal_size.height;
dispatch_desc.enableSharpening = (p_params.sharpness > 1e-6f);
dispatch_desc.sharpness = p_params.sharpness;
dispatch_desc.frameTimeDelta = p_params.delta_time;
dispatch_desc.preExposure = 1.0f;
dispatch_desc.cameraNear = p_params.z_near;
dispatch_desc.cameraFar = p_params.z_far;
dispatch_desc.cameraFovAngleVertical = p_params.fovy;
dispatch_desc.viewSpaceToMetersFactor = 1.0f;
dispatch_desc.enableAutoReactive = false;
dispatch_desc.autoTcThreshold = 1.0f;
dispatch_desc.autoTcScale = 1.0f;
dispatch_desc.autoReactiveScale = 1.0f;
dispatch_desc.autoReactiveMax = 1.0f;
RendererRD::MaterialStorage::store_camera(p_params.reprojection, dispatch_desc.reprojectionMatrix);
FfxErrorCode result = ffxFsr2ContextDispatch(&p_params.context->fsr_context, &dispatch_desc);
ERR_FAIL_COND(result != FFX_OK);
}

View file

@ -0,0 +1,199 @@
/**************************************************************************/
/* fsr2.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 FSR2_RD_H
#define FSR2_RD_H
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_accumulate_pass.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_autogen_reactive_pass.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_compute_luminance_pyramid_pass.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_depth_clip_pass.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_lock_pass.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_rcas_pass.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_reconstruct_previous_depth_pass.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_tcr_autogen_pass.glsl.gen.h"
// This flag doesn't actually control anything GCC specific in FSR2. It determines
// if symbols should be exported, which is not required for Godot.
#ifndef FFX_GCC
#define FFX_GCC
#endif
#include "thirdparty/amd-fsr2/ffx_fsr2.h"
#define FSR2_MAX_QUEUED_FRAMES (4)
#define FSR2_MAX_UNIFORM_BUFFERS (4)
#define FSR2_MAX_BUFFERED_DESCRIPTORS (FFX_FSR2_PASS_COUNT * FSR2_MAX_QUEUED_FRAMES)
#define FSR2_UBO_RING_BUFFER_SIZE (FSR2_MAX_BUFFERED_DESCRIPTORS * FSR2_MAX_UNIFORM_BUFFERS)
namespace RendererRD {
class FSR2Context {
public:
enum ResourceID : uint32_t {
RESOURCE_ID_DYNAMIC = 0xFFFFFFFF
};
struct Resources {
LocalVector<RID> rids;
LocalVector<LocalVector<RID>> mip_slice_rids;
LocalVector<uint32_t> ids;
LocalVector<FfxResourceDescription> descriptions;
LocalVector<uint32_t> dynamic_list;
LocalVector<uint32_t> free_list;
uint32_t add(RID p_rid, bool p_dynamic, uint32_t p_id, FfxResourceDescription p_description) {
uint32_t ret_index;
if (free_list.is_empty()) {
ret_index = rids.size();
uint32_t new_size = ret_index + 1;
rids.resize(new_size);
mip_slice_rids.resize(new_size);
ids.resize(new_size);
descriptions.resize(new_size);
} else {
uint32_t end_index = free_list.size() - 1;
ret_index = free_list[end_index];
free_list.resize(end_index);
}
rids[ret_index] = p_rid;
mip_slice_rids[ret_index].clear();
ids[ret_index] = p_id;
descriptions[ret_index] = p_description;
if (p_dynamic) {
dynamic_list.push_back(ret_index);
}
return ret_index;
}
void remove(uint32_t p_index) {
DEV_ASSERT(p_index < rids.size());
free_list.push_back(p_index);
rids[p_index] = RID();
mip_slice_rids[p_index].clear();
ids[p_index] = 0;
descriptions[p_index] = {};
dynamic_list.erase(p_index);
}
uint32_t size() const {
return rids.size();
}
};
struct Scratch {
Resources resources;
LocalVector<FfxGpuJobDescription> gpu_jobs;
RID ubo_ring_buffer[FSR2_UBO_RING_BUFFER_SIZE];
uint32_t ubo_ring_buffer_index = 0;
FfxDevice device = nullptr;
};
Scratch scratch;
FfxFsr2Context fsr_context;
FfxFsr2ContextDescription fsr_desc;
~FSR2Context();
};
class FSR2Effect {
public:
struct RootSignature {
// Proxy structure to store the shader required by RD that uses the terminology used by the FSR2 API.
RID shader_rid;
};
struct Pipeline {
RID pipeline_rid;
};
struct Pass {
ShaderRD *shader;
RID shader_version;
RootSignature root_signature;
uint32_t shader_variant = 0;
Pipeline pipeline;
Vector<FfxResourceBinding> sampled_bindings;
Vector<FfxResourceBinding> storage_bindings;
Vector<FfxResourceBinding> uniform_bindings;
};
struct Device {
Pass passes[FFX_FSR2_PASS_COUNT];
FfxDeviceCapabilities capabilities;
RID point_clamp_sampler;
RID linear_clamp_sampler;
};
struct Parameters {
FSR2Context *context;
Size2i internal_size;
RID color;
RID depth;
RID velocity;
RID reactive;
RID exposure;
RID output;
float z_near = 0.0f;
float z_far = 0.0f;
float fovy = 0.0f;
Vector2 jitter;
float delta_time = 0.0f;
float sharpness = 0.0f;
bool reset_accumulation = false;
Projection reprojection;
};
FSR2Effect();
~FSR2Effect();
FSR2Context *create_context(Size2i p_internal_size, Size2i p_target_size);
void upscale(const Parameters &p_params);
private:
struct {
Fsr2DepthClipPassShaderRD depth_clip;
Fsr2ReconstructPreviousDepthPassShaderRD reconstruct_previous_depth;
Fsr2LockPassShaderRD lock;
Fsr2AccumulatePassShaderRD accumulate;
Fsr2AccumulatePassShaderRD accumulate_sharpen;
Fsr2RcasPassShaderRD rcas;
Fsr2ComputeLuminancePyramidPassShaderRD compute_luminance_pyramid;
Fsr2AutogenReactivePassShaderRD autogen_reactive;
Fsr2TcrAutogenPassShaderRD tcr_autogen;
} shaders;
Device device;
};
} // namespace RendererRD
#endif // FSR2_RD_H

View file

@ -0,0 +1,254 @@
/**************************************************************************/
/* luminance.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "luminance.h"
#include "../framebuffer_cache_rd.h"
#include "../uniform_set_cache_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
using namespace RendererRD;
Luminance::Luminance(bool p_prefer_raster_effects) {
prefer_raster_effects = p_prefer_raster_effects;
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);
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");
luminance_reduce_modes.push_back("\n");
luminance_reduce_modes.push_back("\n#define WRITE_LUMINANCE\n");
luminance_reduce.shader.initialize(luminance_reduce_modes);
luminance_reduce.shader_version = luminance_reduce.shader.version_create();
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();
}
}
}
Luminance::~Luminance() {
if (prefer_raster_effects) {
luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version);
} else {
luminance_reduce.shader.version_free(luminance_reduce.shader_version);
}
}
void Luminance::LuminanceBuffers::set_prefer_raster_effects(bool p_prefer_raster_effects) {
prefer_raster_effects = p_prefer_raster_effects;
}
void Luminance::LuminanceBuffers::configure(RenderSceneBuffersRD *p_render_buffers) {
Size2i internal_size = p_render_buffers->get_internal_size();
int w = internal_size.x;
int h = internal_size.y;
while (true) {
w = MAX(w / 8, 1);
h = MAX(h / 8, 1);
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R32_SFLOAT;
tf.width = w;
tf.height = h;
bool final = w == 1 && h == 1;
if (prefer_raster_effects) {
tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
} else {
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
if (final) {
tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT;
}
}
RID texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
reduce.push_back(texture);
if (final) {
current = RD::get_singleton()->texture_create(tf, RD::TextureView());
break;
}
}
}
void Luminance::LuminanceBuffers::free_data() {
for (int i = 0; i < reduce.size(); i++) {
RD::get_singleton()->free(reduce[i]);
}
reduce.clear();
if (current.is_valid()) {
RD::get_singleton()->free(current);
current = RID();
}
}
Ref<Luminance::LuminanceBuffers> Luminance::get_luminance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers) {
if (p_render_buffers->has_custom_data(RB_LUMINANCE_BUFFERS)) {
return p_render_buffers->get_custom_data(RB_LUMINANCE_BUFFERS);
}
Ref<LuminanceBuffers> buffers;
buffers.instantiate();
buffers->set_prefer_raster_effects(prefer_raster_effects);
buffers->configure(p_render_buffers.ptr());
p_render_buffers->set_custom_data(RB_LUMINANCE_BUFFERS, buffers);
return buffers;
}
RID Luminance::get_current_luminance_buffer(Ref<RenderSceneBuffersRD> p_render_buffers) {
if (p_render_buffers->has_custom_data(RB_LUMINANCE_BUFFERS)) {
Ref<LuminanceBuffers> buffers = p_render_buffers->get_custom_data(RB_LUMINANCE_BUFFERS);
return buffers->current;
}
return RID();
}
void Luminance::luminance_reduction(RID p_source_texture, const Size2i p_source_size, Ref<LuminanceBuffers> p_luminance_buffers, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
// setup our uniforms
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
if (prefer_raster_effects) {
LuminanceReduceRasterPushConstant push_constant;
memset(&push_constant, 0, sizeof(LuminanceReduceRasterPushConstant));
push_constant.max_luminance = p_max_luminance;
push_constant.min_luminance = p_min_luminance;
push_constant.exposure_adjust = p_adjust;
for (int i = 0; i < p_luminance_buffers->reduce.size(); i++) {
push_constant.source_size[0] = i == 0 ? p_source_size.x : push_constant.dest_size[0];
push_constant.source_size[1] = i == 0 ? p_source_size.y : push_constant.dest_size[1];
push_constant.dest_size[0] = MAX(push_constant.source_size[0] / 8, 1);
push_constant.dest_size[1] = MAX(push_constant.source_size[1] / 8, 1);
bool final = !p_set && (push_constant.dest_size[0] == 1) && (push_constant.dest_size[1] == 1);
LuminanceReduceRasterMode mode = final ? LUMINANCE_REDUCE_FRAGMENT_FINAL : (i == 0 ? LUMINANCE_REDUCE_FRAGMENT_FIRST : LUMINANCE_REDUCE_FRAGMENT);
RID shader = luminance_reduce_raster.shader.version_get_shader(luminance_reduce_raster.shader_version, mode);
RID framebuffer = FramebufferCacheRD::get_singleton()->get_cache(p_luminance_buffers->reduce[i]);
RD::Uniform u_source_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, i == 0 ? p_source_texture : p_luminance_buffers->reduce[i - 1] }));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, 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(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_texture), 0);
if (final) {
RD::Uniform u_current_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_luminance_buffers->current }));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_current_texture), 1);
}
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(LuminanceReduceRasterPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
} else {
LuminanceReducePushConstant push_constant;
memset(&push_constant, 0, sizeof(LuminanceReducePushConstant));
push_constant.source_size[0] = p_source_size.x;
push_constant.source_size[1] = p_source_size.y;
push_constant.max_luminance = p_max_luminance;
push_constant.min_luminance = p_min_luminance;
push_constant.exposure_adjust = p_adjust;
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
for (int i = 0; i < p_luminance_buffers->reduce.size(); i++) {
RID shader;
if (i == 0) {
shader = luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, LUMINANCE_REDUCE_READ);
RD::Uniform u_source_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_texture }));
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE_READ]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_texture), 0);
} else {
RD::get_singleton()->compute_list_add_barrier(compute_list); //needs barrier, wait until previous is done
if (i == p_luminance_buffers->reduce.size() - 1 && !p_set) {
shader = luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, LUMINANCE_REDUCE_WRITE);
RD::Uniform u_current_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_luminance_buffers->current }));
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE_WRITE]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_current_texture), 2);
} else {
shader = luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, LUMINANCE_REDUCE);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE]);
}
RD::Uniform u_source_texture(RD::UNIFORM_TYPE_IMAGE, 0, p_luminance_buffers->reduce[i - 1]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_texture), 0);
}
RD::Uniform u_reduce_texture(RD::UNIFORM_TYPE_IMAGE, 0, p_luminance_buffers->reduce[i]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_reduce_texture), 1);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(LuminanceReducePushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.source_size[0], push_constant.source_size[1], 1);
push_constant.source_size[0] = MAX(push_constant.source_size[0] / 8, 1);
push_constant.source_size[1] = MAX(push_constant.source_size[1] / 8, 1);
}
RD::get_singleton()->compute_list_end();
}
SWAP(p_luminance_buffers->current, p_luminance_buffers->reduce.write[p_luminance_buffers->reduce.size() - 1]);
}

View file

@ -0,0 +1,120 @@
/**************************************************************************/
/* luminance.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 LUMINANCE_RD_H
#define LUMINANCE_RD_H
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/luminance_reduce.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
#define RB_LUMINANCE_BUFFERS SNAME("luminance_buffers")
namespace RendererRD {
class Luminance {
private:
bool prefer_raster_effects;
enum LuminanceReduceMode {
LUMINANCE_REDUCE_READ,
LUMINANCE_REDUCE,
LUMINANCE_REDUCE_WRITE,
LUMINANCE_REDUCE_MAX
};
struct LuminanceReducePushConstant {
int32_t source_size[2];
float max_luminance;
float min_luminance;
float exposure_adjust;
float pad[3];
};
struct LuminanceReduce {
LuminanceReduceShaderRD shader;
RID shader_version;
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 {
LuminanceReduceRasterShaderRD shader;
RID shader_version;
PipelineCacheRD pipelines[LUMINANCE_REDUCE_FRAGMENT_MAX];
} luminance_reduce_raster;
public:
class LuminanceBuffers : public RenderBufferCustomDataRD {
GDCLASS(LuminanceBuffers, RenderBufferCustomDataRD);
private:
bool prefer_raster_effects;
public:
Vector<RID> reduce;
RID current;
virtual void configure(RenderSceneBuffersRD *p_render_buffers) override;
virtual void free_data() override;
void set_prefer_raster_effects(bool p_prefer_raster_effects);
};
Ref<LuminanceBuffers> get_luminance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers);
RID get_current_luminance_buffer(Ref<RenderSceneBuffersRD> p_render_buffers);
void luminance_reduction(RID p_source_texture, const Size2i p_source_size, Ref<LuminanceBuffers> p_luminance_buffers, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
Luminance(bool p_prefer_raster_effects);
~Luminance();
};
} // namespace RendererRD
#endif // LUMINANCE_RD_H

View file

@ -0,0 +1,130 @@
/**************************************************************************/
/* resolve.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "resolve.h"
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
using namespace RendererRD;
Resolve::Resolve() {
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_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));
}
}
Resolve::~Resolve() {
resolve.shader.version_free(resolve.shader_version);
}
void Resolve::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) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
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;
// setup our uniforms
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RD::Uniform u_source_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_depth }));
RD::Uniform u_source_normal_roughness(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, Vector<RID>({ default_sampler, p_source_normal_roughness }));
RD::Uniform u_dest_depth(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_dest_depth }));
RD::Uniform u_dest_normal_roughness(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_dest_normal_roughness }));
ResolveMode mode = p_source_voxel_gi.is_valid() ? RESOLVE_MODE_GI_VOXEL_GI : RESOLVE_MODE_GI;
RID shader = resolve.shader.version_get_shader(resolve.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, resolve.pipelines[mode]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_depth, u_source_normal_roughness), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_dest_depth, u_dest_normal_roughness), 1);
if (p_source_voxel_gi.is_valid()) {
RD::Uniform u_source_voxel_gi(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_voxel_gi }));
RD::Uniform u_dest_voxel_gi(RD::UNIFORM_TYPE_IMAGE, 0, p_dest_voxel_gi);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_source_voxel_gi), 2);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_dest_voxel_gi), 3);
}
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();
}
void Resolve::resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
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;
// setup our uniforms
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RD::Uniform u_source_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_depth }));
RD::Uniform u_dest_depth(RD::UNIFORM_TYPE_IMAGE, 0, p_dest_depth);
ResolveMode mode = RESOLVE_MODE_DEPTH;
RID shader = resolve.shader.version_get_shader(resolve.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, resolve.pipelines[mode]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_depth), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_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();
}

View file

@ -0,0 +1,74 @@
/**************************************************************************/
/* resolve.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 RESOLVE_RD_H
#define RESOLVE_RD_H
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/resolve.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
namespace RendererRD {
class Resolve {
private:
struct ResolvePushConstant {
int32_t screen_size[2];
int32_t samples;
uint32_t pad;
};
enum ResolveMode {
RESOLVE_MODE_GI,
RESOLVE_MODE_GI_VOXEL_GI,
RESOLVE_MODE_DEPTH,
RESOLVE_MODE_MAX
};
struct ResolveShader {
ResolvePushConstant push_constant;
ResolveShaderRD shader;
RID shader_version;
RID pipelines[RESOLVE_MODE_MAX]; //3 quality levels
} resolve;
public:
Resolve();
~Resolve();
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);
void resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples);
};
} // namespace RendererRD
#endif // RESOLVE_RD_H

View file

@ -0,0 +1,79 @@
/**************************************************************************/
/* roughness_limiter.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "roughness_limiter.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
using namespace RendererRD;
RoughnessLimiter::RoughnessLimiter() {
// Initialize roughness limiter
Vector<String> shader_modes;
shader_modes.push_back("");
shader.initialize(shader_modes);
shader_version = shader.version_create();
pipeline = RD::get_singleton()->compute_pipeline_create(shader.version_get_shader(shader_version, 0));
}
RoughnessLimiter::~RoughnessLimiter() {
shader.version_free(shader_version);
}
void RoughnessLimiter::roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
push_constant.screen_size[0] = p_size.x;
push_constant.screen_size[1] = p_size.y;
push_constant.curve = p_curve;
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RID rl_shader = shader.version_get_shader(shader_version, 0);
RD::Uniform u_source_normal(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_normal }));
RD::Uniform u_roughness(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_roughness }));
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipeline);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(rl_shader, 0, u_source_normal), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(rl_shader, 1, u_roughness), 1);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RoughnessLimiterPushConstant)); //not used but set anyway
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_size.x, p_size.y, 1);
RD::get_singleton()->compute_list_end();
}

View file

@ -0,0 +1,67 @@
/**************************************************************************/
/* roughness_limiter.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 ROUGHNESS_LIMITER_RD_H
#define ROUGHNESS_LIMITER_RD_H
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/roughness_limiter.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
namespace RendererRD {
// Note, this logic is unused at the time of writing. It should be re-incorporated into the renderer at some point.
class RoughnessLimiter {
private:
struct RoughnessLimiterPushConstant {
int32_t screen_size[2];
float curve;
uint32_t pad;
};
RoughnessLimiterPushConstant push_constant;
RoughnessLimiterShaderRD shader;
RID shader_version;
RID pipeline;
protected:
public:
RoughnessLimiter();
~RoughnessLimiter();
void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
};
} // namespace RendererRD
#endif // ROUGHNESS_LIMITER_RD_H

View file

@ -0,0 +1,124 @@
/**************************************************************************/
/* sort_effects.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "sort_effects.h"
// #include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
using namespace RendererRD;
SortEffects::SortEffects() {
Vector<String> sort_modes;
sort_modes.push_back("\n#define MODE_SORT_BLOCK\n");
sort_modes.push_back("\n#define MODE_SORT_STEP\n");
sort_modes.push_back("\n#define MODE_SORT_INNER\n");
shader.initialize(sort_modes);
shader_version = shader.version_create();
for (int i = 0; i < SORT_MODE_MAX; i++) {
pipelines[i] = RD::get_singleton()->compute_pipeline_create(shader.version_get_shader(shader_version, i));
}
}
SortEffects::~SortEffects() {
shader.version_free(shader_version);
}
void SortEffects::sort_buffer(RID p_uniform_set, int p_size) {
PushConstant push_constant;
push_constant.total_elements = p_size;
bool done = true;
int numThreadGroups = ((p_size - 1) >> 9) + 1;
if (numThreadGroups > 1) {
done = false;
}
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[SORT_MODE_BLOCK]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_uniform_set, 1);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, numThreadGroups, 1, 1);
int presorted = 512;
while (!done) {
RD::get_singleton()->compute_list_add_barrier(compute_list);
done = true;
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[SORT_MODE_STEP]);
numThreadGroups = 0;
if (p_size > presorted) {
if (p_size > presorted * 2) {
done = false;
}
int pow2 = presorted;
while (pow2 < p_size) {
pow2 *= 2;
}
numThreadGroups = pow2 >> 9;
}
unsigned int nMergeSize = presorted * 2;
for (unsigned int nMergeSubSize = nMergeSize >> 1; nMergeSubSize > 256; nMergeSubSize = nMergeSubSize >> 1) {
push_constant.job_params[0] = nMergeSubSize;
if (nMergeSubSize == nMergeSize >> 1) {
push_constant.job_params[1] = (2 * nMergeSubSize - 1);
push_constant.job_params[2] = -1;
} else {
push_constant.job_params[1] = nMergeSubSize;
push_constant.job_params[2] = 1;
}
push_constant.job_params[3] = 0;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, numThreadGroups, 1, 1);
RD::get_singleton()->compute_list_add_barrier(compute_list);
}
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[SORT_MODE_INNER]);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, numThreadGroups, 1, 1);
presorted *= 2;
}
RD::get_singleton()->compute_list_end();
}

View file

@ -0,0 +1,71 @@
/**************************************************************************/
/* sort_effects.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 SORT_EFFECTS_RD_H
#define SORT_EFFECTS_RD_H
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/sort.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
namespace RendererRD {
class SortEffects {
private:
enum SortMode {
SORT_MODE_BLOCK,
SORT_MODE_STEP,
SORT_MODE_INNER,
SORT_MODE_MAX
};
struct PushConstant {
uint32_t total_elements;
uint32_t pad[3];
int32_t job_params[4];
};
SortShaderRD shader;
RID shader_version;
RID pipelines[SORT_MODE_MAX];
protected:
public:
SortEffects();
~SortEffects();
void sort_buffer(RID p_uniform_set, int p_size);
};
} // namespace RendererRD
#endif // SORT_EFFECTS_RD_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,533 @@
/**************************************************************************/
/* ss_effects.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 SS_EFFECTS_RD_H
#define SS_EFFECTS_RD_H
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_filter.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/ssao.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/ssao_blur.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/ssil.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
#define RB_SCOPE_SSDS SNAME("rb_ssds")
#define RB_SCOPE_SSIL SNAME("rb_ssil")
#define RB_SCOPE_SSAO SNAME("rb_ssao")
#define RB_SCOPE_SSR SNAME("rb_ssr")
#define RB_LINEAR_DEPTH SNAME("linear_depth")
#define RB_FINAL SNAME("final")
#define RB_LAST_FRAME SNAME("last_frame")
#define RB_DEINTERLEAVED SNAME("deinterleaved")
#define RB_DEINTERLEAVED_PONG SNAME("deinterleaved_pong")
#define RB_EDGES SNAME("edges")
#define RB_IMPORTANCE_MAP SNAME("importance_map")
#define RB_IMPORTANCE_PONG SNAME("importance_pong")
#define RB_DEPTH_SCALED SNAME("depth_scaled")
#define RB_NORMAL_SCALED SNAME("normal_scaled")
#define RB_BLUR_RADIUS SNAME("blur_radius")
#define RB_INTERMEDIATE SNAME("intermediate")
#define RB_OUTPUT SNAME("output")
class RenderSceneBuffersRD;
namespace RendererRD {
class SSEffects {
private:
static SSEffects *singleton;
public:
static SSEffects *get_singleton() { return singleton; }
SSEffects();
~SSEffects();
/* SS Downsampler */
void downsample_depth(Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_view, const Projection &p_projection);
/* SSIL */
void ssil_set_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to);
struct SSILRenderBuffers {
bool half_size = false;
int buffer_width;
int buffer_height;
int half_buffer_width;
int half_buffer_height;
};
struct SSILSettings {
float radius = 1.0;
float intensity = 2.0;
float sharpness = 0.98;
float normal_rejection = 1.0;
Size2i full_screen_size;
};
void ssil_allocate_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, SSILRenderBuffers &p_ssil_buffers, const SSILSettings &p_settings);
void screen_space_indirect_lighting(Ref<RenderSceneBuffersRD> p_render_buffers, SSILRenderBuffers &p_ssil_buffers, uint32_t p_view, RID p_normal_buffer, const Projection &p_projection, const Projection &p_last_projection, const SSILSettings &p_settings);
/* SSAO */
void ssao_set_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);
struct SSAORenderBuffers {
bool half_size = false;
int buffer_width;
int buffer_height;
int half_buffer_width;
int half_buffer_height;
};
struct SSAOSettings {
float radius = 1.0;
float intensity = 2.0;
float power = 1.5;
float detail = 0.5;
float horizon = 0.06;
float sharpness = 0.98;
Size2i full_screen_size;
};
void ssao_allocate_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORenderBuffers &p_ssao_buffers, const SSAOSettings &p_settings);
void generate_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORenderBuffers &p_ssao_buffers, uint32_t p_view, RID p_normal_buffer, const Projection &p_projection, const SSAOSettings &p_settings);
/* Screen Space Reflection */
void ssr_set_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality);
struct SSRRenderBuffers {
Size2i size;
RenderingServer::EnvironmentSSRRoughnessQuality roughness_quality = RenderingServer::ENV_SSR_ROUGHNESS_QUALITY_DISABLED;
};
void ssr_allocate_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format);
void screen_space_reflection(Ref<RenderSceneBuffersRD> p_render_buffers, SSRRenderBuffers &p_ssr_buffers, const RID *p_normal_roughness_slices, const RID *p_metallic_slices, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const Projection *p_projections, const Vector3 *p_eye_offsets);
/* subsurface scattering */
void sss_set_quality(RS::SubSurfaceScatteringQuality p_quality);
RS::SubSurfaceScatteringQuality sss_get_quality() const;
void sss_set_scale(float p_scale, float p_depth_scale);
void sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size);
private:
/* Settings */
RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
bool ssao_half_size = false;
float ssao_adaptive_target = 0.5;
int ssao_blur_passes = 2;
float ssao_fadeout_from = 50.0;
float ssao_fadeout_to = 300.0;
RS::EnvironmentSSILQuality ssil_quality = RS::ENV_SSIL_QUALITY_MEDIUM;
bool ssil_half_size = false;
float ssil_adaptive_target = 0.5;
int ssil_blur_passes = 4;
float ssil_fadeout_from = 50.0;
float ssil_fadeout_to = 300.0;
RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGHNESS_QUALITY_LOW;
RS::SubSurfaceScatteringQuality sss_quality = RS::SUB_SURFACE_SCATTERING_QUALITY_MEDIUM;
float sss_scale = 0.05;
float sss_depth_scale = 0.01;
/* SS Downsampler */
struct SSEffectsDownsamplePushConstant {
float pixel_size[2];
float z_far;
float z_near;
uint32_t orthogonal;
float radius_sq;
uint32_t pad[2];
};
enum SSEffectsMode {
SS_EFFECTS_DOWNSAMPLE,
SS_EFFECTS_DOWNSAMPLE_HALF_RES,
SS_EFFECTS_DOWNSAMPLE_MIPMAP,
SS_EFFECTS_DOWNSAMPLE_MIPMAP_HALF_RES,
SS_EFFECTS_DOWNSAMPLE_HALF,
SS_EFFECTS_DOWNSAMPLE_HALF_RES_HALF,
SS_EFFECTS_DOWNSAMPLE_FULL_MIPS,
SS_EFFECTS_MAX
};
struct SSEffectsGatherConstants {
float rotation_matrices[80]; //5 vec4s * 4
};
struct SSEffectsShader {
SSEffectsDownsamplePushConstant downsample_push_constant;
SsEffectsDownsampleShaderRD downsample_shader;
RID downsample_shader_version;
bool used_half_size_last_frame = false;
bool used_mips_last_frame = false;
bool used_full_mips_last_frame = false;
RID gather_constants_buffer;
RID mirror_sampler;
RID pipelines[SS_EFFECTS_MAX];
} ss_effects;
/* SSIL */
enum SSILMode {
SSIL_GATHER,
SSIL_GATHER_BASE,
SSIL_GATHER_ADAPTIVE,
SSIL_GENERATE_IMPORTANCE_MAP,
SSIL_PROCESS_IMPORTANCE_MAPA,
SSIL_PROCESS_IMPORTANCE_MAPB,
SSIL_BLUR_PASS,
SSIL_BLUR_PASS_SMART,
SSIL_BLUR_PASS_WIDE,
SSIL_INTERLEAVE,
SSIL_INTERLEAVE_SMART,
SSIL_INTERLEAVE_HALF,
SSIL_MAX
};
struct SSILGatherPushConstant {
int32_t screen_size[2];
int pass;
int quality;
float half_screen_pixel_size[2];
float half_screen_pixel_size_x025[2];
float NDC_to_view_mul[2];
float NDC_to_view_add[2];
float pad2[2];
float z_near;
float z_far;
float radius;
float intensity;
int size_multiplier;
int pad;
float fade_out_mul;
float fade_out_add;
float normal_rejection_amount;
float inv_radius_near_limit;
uint32_t is_orthogonal;
float neg_inv_radius;
float load_counter_avg_div;
float adaptive_sample_limit;
int32_t pass_coord_offset[2];
float pass_uv_offset[2];
};
struct SSILImportanceMapPushConstant {
float half_screen_pixel_size[2];
float intensity;
float pad;
};
struct SSILBlurPushConstant {
float edge_sharpness;
float pad;
float half_screen_pixel_size[2];
};
struct SSILInterleavePushConstant {
float inv_sharpness;
uint32_t size_modifier;
float pixel_size[2];
};
struct SSILProjectionUniforms {
float inv_last_frame_projection_matrix[16];
};
struct SSIL {
SSILGatherPushConstant gather_push_constant;
SsilShaderRD gather_shader;
RID gather_shader_version;
RID projection_uniform_buffer;
SSILImportanceMapPushConstant importance_map_push_constant;
SsilImportanceMapShaderRD importance_map_shader;
RID importance_map_shader_version;
RID importance_map_load_counter;
RID counter_uniform_set;
SSILBlurPushConstant blur_push_constant;
SsilBlurShaderRD blur_shader;
RID blur_shader_version;
SSILInterleavePushConstant interleave_push_constant;
SsilInterleaveShaderRD interleave_shader;
RID interleave_shader_version;
RID pipelines[SSIL_MAX];
} ssil;
void gather_ssil(RD::ComputeListID p_compute_list, const RID *p_ssil_slices, const RID *p_edges_slices, const SSILSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set, RID p_projection_uniform_set);
/* SSAO */
enum SSAOMode {
SSAO_GATHER,
SSAO_GATHER_BASE,
SSAO_GATHER_ADAPTIVE,
SSAO_GENERATE_IMPORTANCE_MAP,
SSAO_PROCESS_IMPORTANCE_MAPA,
SSAO_PROCESS_IMPORTANCE_MAPB,
SSAO_BLUR_PASS,
SSAO_BLUR_PASS_SMART,
SSAO_BLUR_PASS_WIDE,
SSAO_INTERLEAVE,
SSAO_INTERLEAVE_SMART,
SSAO_INTERLEAVE_HALF,
SSAO_MAX
};
struct SSAOGatherPushConstant {
int32_t screen_size[2];
int pass;
int quality;
float half_screen_pixel_size[2];
int size_multiplier;
float detail_intensity;
float NDC_to_view_mul[2];
float NDC_to_view_add[2];
float pad[2];
float half_screen_pixel_size_x025[2];
float radius;
float intensity;
float shadow_power;
float shadow_clamp;
float fade_out_mul;
float fade_out_add;
float horizon_angle_threshold;
float inv_radius_near_limit;
uint32_t is_orthogonal;
float neg_inv_radius;
float load_counter_avg_div;
float adaptive_sample_limit;
int32_t pass_coord_offset[2];
float pass_uv_offset[2];
};
struct SSAOImportanceMapPushConstant {
float half_screen_pixel_size[2];
float intensity;
float power;
};
struct SSAOBlurPushConstant {
float edge_sharpness;
float pad;
float half_screen_pixel_size[2];
};
struct SSAOInterleavePushConstant {
float inv_sharpness;
uint32_t size_modifier;
float pixel_size[2];
};
struct SSAO {
SSAOGatherPushConstant gather_push_constant;
SsaoShaderRD gather_shader;
RID gather_shader_version;
SSAOImportanceMapPushConstant importance_map_push_constant;
SsaoImportanceMapShaderRD importance_map_shader;
RID importance_map_shader_version;
RID importance_map_load_counter;
RID counter_uniform_set;
SSAOBlurPushConstant blur_push_constant;
SsaoBlurShaderRD blur_shader;
RID blur_shader_version;
SSAOInterleavePushConstant interleave_push_constant;
SsaoInterleaveShaderRD interleave_shader;
RID interleave_shader_version;
RID pipelines[SSAO_MAX];
} ssao;
void gather_ssao(RD::ComputeListID p_compute_list, const RID *p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set);
/* Screen Space Reflection */
enum SSRShaderSpecializations {
SSR_MULTIVIEW = 1 << 0,
SSR_VARIATIONS = 2,
};
struct ScreenSpaceReflectionSceneData {
float projection[2][16];
float inv_projection[2][16];
float eye_offset[2][4];
};
// SSR Scale
struct ScreenSpaceReflectionScalePushConstant {
int32_t screen_size[2];
float camera_z_near;
float camera_z_far;
uint32_t orthogonal;
uint32_t filter;
uint32_t view_index;
uint32_t pad1;
};
struct ScreenSpaceReflectionScale {
ScreenSpaceReflectionScaleShaderRD shader;
RID shader_version;
RID pipelines[SSR_VARIATIONS];
} ssr_scale;
// SSR main
enum ScreenSpaceReflectionMode {
SCREEN_SPACE_REFLECTION_NORMAL,
SCREEN_SPACE_REFLECTION_ROUGH,
SCREEN_SPACE_REFLECTION_MAX,
};
struct ScreenSpaceReflectionPushConstant {
float proj_info[4]; // 16 - 16
int32_t screen_size[2]; // 8 - 24
float camera_z_near; // 4 - 28
float camera_z_far; // 4 - 32
int32_t num_steps; // 4 - 36
float depth_tolerance; // 4 - 40
float distance_fade; // 4 - 44
float curve_fade_in; // 4 - 48
uint32_t orthogonal; // 4 - 52
float filter_mipmap_levels; // 4 - 56
uint32_t use_half_res; // 4 - 60
uint32_t view_index; // 4 - 64
// float projection[16]; // this is in our ScreenSpaceReflectionSceneData now
};
struct ScreenSpaceReflection {
ScreenSpaceReflectionShaderRD shader;
RID shader_version;
RID pipelines[SSR_VARIATIONS][SCREEN_SPACE_REFLECTION_MAX];
RID ubo;
} ssr;
// SSR Filter
struct ScreenSpaceReflectionFilterPushConstant {
float proj_info[4]; // 16 - 16
uint32_t orthogonal; // 4 - 20
float edge_tolerance; // 4 - 24
int32_t increment; // 4 - 28
uint32_t view_index; // 4 - 32
int32_t screen_size[2]; // 8 - 40
uint32_t vertical; // 4 - 44
uint32_t steps; // 4 - 48
};
enum SSRReflectionMode {
SCREEN_SPACE_REFLECTION_FILTER_HORIZONTAL,
SCREEN_SPACE_REFLECTION_FILTER_VERTICAL,
SCREEN_SPACE_REFLECTION_FILTER_MAX,
};
struct ScreenSpaceReflectionFilter {
ScreenSpaceReflectionFilterShaderRD shader;
RID shader_version;
RID pipelines[SSR_VARIATIONS][SCREEN_SPACE_REFLECTION_FILTER_MAX];
} ssr_filter;
/* Subsurface scattering */
struct SubSurfaceScatteringPushConstant {
int32_t screen_size[2];
float camera_z_far;
float camera_z_near;
uint32_t vertical;
uint32_t orthogonal;
float unit_size;
float scale;
float depth_scale;
uint32_t pad[3];
};
struct SubSurfaceScattering {
SubSurfaceScatteringPushConstant push_constant;
SubsurfaceScatteringShaderRD shader;
RID shader_version;
RID pipelines[3]; //3 quality levels
} sss;
};
} // namespace RendererRD
#endif // SS_EFFECTS_RD_H

View file

@ -0,0 +1,124 @@
/**************************************************************************/
/* taa.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "taa.h"
#include "servers/rendering/renderer_rd/effects/copy_effects.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
using namespace RendererRD;
TAA::TAA() {
Vector<String> taa_modes;
taa_modes.push_back("\n#define MODE_TAA_RESOLVE");
taa_shader.initialize(taa_modes);
shader_version = taa_shader.version_create();
pipeline = RD::get_singleton()->compute_pipeline_create(taa_shader.version_get_shader(shader_version, 0));
}
TAA::~TAA() {
taa_shader.version_free(shader_version);
}
void TAA::resolve(RID p_frame, RID p_temp, RID p_depth, RID p_velocity, RID p_prev_velocity, RID p_history, Size2 p_resolution, float p_z_near, float p_z_far) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
RID shader = taa_shader.version_get_shader(shader_version, 0);
ERR_FAIL_COND(shader.is_null());
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
TAAResolvePushConstant push_constant;
memset(&push_constant, 0, sizeof(TAAResolvePushConstant));
push_constant.resolution_width = p_resolution.width;
push_constant.resolution_height = p_resolution.height;
push_constant.disocclusion_threshold = 0.025f;
push_constant.disocclusion_scale = 10.0f;
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipeline);
RD::Uniform u_frame_source(RD::UNIFORM_TYPE_IMAGE, 0, { p_frame });
RD::Uniform u_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, { default_sampler, p_depth });
RD::Uniform u_velocity(RD::UNIFORM_TYPE_IMAGE, 2, { p_velocity });
RD::Uniform u_prev_velocity(RD::UNIFORM_TYPE_IMAGE, 3, { p_prev_velocity });
RD::Uniform u_history(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 4, { default_sampler, p_history });
RD::Uniform u_frame_dest(RD::UNIFORM_TYPE_IMAGE, 5, { p_temp });
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_frame_source, u_depth, u_velocity, u_prev_velocity, u_history, u_frame_dest), 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(TAAResolvePushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_resolution.width, p_resolution.height, 1);
RD::get_singleton()->compute_list_end();
}
void TAA::process(Ref<RenderSceneBuffersRD> p_render_buffers, RD::DataFormat p_format, float p_z_near, float p_z_far) {
CopyEffects *copy_effects = CopyEffects::get_singleton();
uint32_t view_count = p_render_buffers->get_view_count();
Size2i internal_size = p_render_buffers->get_internal_size();
Size2i target_size = p_render_buffers->get_target_size();
bool just_allocated = false;
if (!p_render_buffers->has_texture(SNAME("taa"), SNAME("history"))) {
uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
p_render_buffers->create_texture(SNAME("taa"), SNAME("history"), p_format, usage_bits);
p_render_buffers->create_texture(SNAME("taa"), SNAME("temp"), p_format, usage_bits);
p_render_buffers->create_texture(SNAME("taa"), SNAME("prev_velocity"), RD::DATA_FORMAT_R16G16_SFLOAT, usage_bits);
just_allocated = true;
}
RD::get_singleton()->draw_command_begin_label("TAA");
for (uint32_t v = 0; v < view_count; v++) {
// Get our (cached) slices
RID internal_texture = p_render_buffers->get_internal_texture(v);
RID velocity_buffer = p_render_buffers->get_velocity_buffer(false, v);
RID taa_history = p_render_buffers->get_texture_slice(SNAME("taa"), SNAME("history"), v, 0);
RID taa_prev_velocity = p_render_buffers->get_texture_slice(SNAME("taa"), SNAME("prev_velocity"), v, 0);
if (!just_allocated) {
RID depth_texture = p_render_buffers->get_depth_texture(v);
RID taa_temp = p_render_buffers->get_texture_slice(SNAME("taa"), SNAME("temp"), v, 0);
resolve(internal_texture, taa_temp, depth_texture, velocity_buffer, taa_prev_velocity, taa_history, Size2(internal_size.x, internal_size.y), p_z_near, p_z_far);
copy_effects->copy_to_rect(taa_temp, internal_texture, Rect2(0, 0, internal_size.x, internal_size.y));
}
copy_effects->copy_to_rect(internal_texture, taa_history, Rect2(0, 0, internal_size.x, internal_size.y));
copy_effects->copy_to_rect(velocity_buffer, taa_prev_velocity, Rect2(0, 0, target_size.x, target_size.y));
}
RD::get_singleton()->draw_command_end_label();
}

View file

@ -0,0 +1,67 @@
/**************************************************************************/
/* taa.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 TAA_RD_H
#define TAA_RD_H
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
namespace RendererRD {
class TAA {
public:
TAA();
~TAA();
void process(Ref<RenderSceneBuffersRD> p_render_buffers, RD::DataFormat p_format, float p_z_near, float p_z_far);
private:
struct TAAResolvePushConstant {
float resolution_width;
float resolution_height;
float disocclusion_threshold;
float disocclusion_scale;
};
TaaResolveShaderRD taa_shader;
RID shader_version;
RID pipeline;
void resolve(RID p_frame, RID p_temp, RID p_depth, RID p_velocity, RID p_prev_velocity, RID p_history, Size2 p_resolution, float p_z_near, float p_z_far);
};
} // namespace RendererRD
#endif // TAA_RD_H

View file

@ -0,0 +1,259 @@
/**************************************************************************/
/* tone_mapper.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "tone_mapper.h"
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
using namespace RendererRD;
ToneMapper::ToneMapper() {
{
// Initialize tonemapper
Vector<String> tonemap_modes;
tonemap_modes.push_back("\n");
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 USE_MULTIVIEW\n");
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n");
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define SUBPASS\n");
tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define SUBPASS\n#define USE_1D_LUT\n");
tonemap.shader.initialize(tonemap_modes);
if (!RendererCompositorRD::get_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++) {
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();
}
}
}
}
ToneMapper::~ToneMapper() {
tonemap.shader.version_free(tonemap.shader_version);
}
void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant));
tonemap.push_constant.flags |= p_settings.use_bcs ? TONEMAP_FLAG_USE_BCS : 0;
tonemap.push_constant.bcs[0] = p_settings.brightness;
tonemap.push_constant.bcs[1] = p_settings.contrast;
tonemap.push_constant.bcs[2] = p_settings.saturation;
tonemap.push_constant.flags |= p_settings.use_glow ? TONEMAP_FLAG_USE_GLOW : 0;
tonemap.push_constant.glow_intensity = p_settings.glow_intensity;
tonemap.push_constant.glow_map_strength = p_settings.glow_map_strength;
tonemap.push_constant.glow_levels[0] = p_settings.glow_levels[0]; // clean this up to just pass by pointer or something
tonemap.push_constant.glow_levels[1] = p_settings.glow_levels[1];
tonemap.push_constant.glow_levels[2] = p_settings.glow_levels[2];
tonemap.push_constant.glow_levels[3] = p_settings.glow_levels[3];
tonemap.push_constant.glow_levels[4] = p_settings.glow_levels[4];
tonemap.push_constant.glow_levels[5] = p_settings.glow_levels[5];
tonemap.push_constant.glow_levels[6] = p_settings.glow_levels[6];
tonemap.push_constant.glow_texture_size[0] = p_settings.glow_texture_size.x;
tonemap.push_constant.glow_texture_size[1] = p_settings.glow_texture_size.y;
tonemap.push_constant.glow_mode = p_settings.glow_mode;
int mode = p_settings.glow_use_bicubic_upscale ? TONEMAP_MODE_BICUBIC_GLOW_FILTER : TONEMAP_MODE_NORMAL;
if (p_settings.use_1d_color_correction) {
mode += 2;
}
tonemap.push_constant.tonemapper = p_settings.tonemap_mode;
tonemap.push_constant.flags |= p_settings.use_auto_exposure ? TONEMAP_FLAG_USE_AUTO_EXPOSURE : 0;
tonemap.push_constant.exposure = p_settings.exposure;
tonemap.push_constant.white = p_settings.white;
tonemap.push_constant.auto_exposure_scale = p_settings.auto_exposure_scale;
tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier;
tonemap.push_constant.flags |= p_settings.use_color_correction ? TONEMAP_FLAG_USE_COLOR_CORRECTION : 0;
tonemap.push_constant.flags |= p_settings.use_fxaa ? TONEMAP_FLAG_USE_FXAA : 0;
tonemap.push_constant.flags |= p_settings.use_debanding ? TONEMAP_FLAG_USE_DEBANDING : 0;
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;
tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0;
if (p_settings.view_count > 1) {
// Use USE_MULTIVIEW versions
mode += 6;
}
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RD::Uniform u_source_color(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_color }));
RD::Uniform u_exposure_texture;
u_exposure_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u_exposure_texture.binding = 0;
u_exposure_texture.append_id(default_sampler);
u_exposure_texture.append_id(p_settings.exposure_texture);
RD::Uniform u_glow_texture;
u_glow_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u_glow_texture.binding = 0;
u_glow_texture.append_id(default_mipmap_sampler);
u_glow_texture.append_id(p_settings.glow_texture);
RD::Uniform u_glow_map;
u_glow_map.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u_glow_map.binding = 1;
u_glow_map.append_id(default_mipmap_sampler);
u_glow_map.append_id(p_settings.glow_map);
RD::Uniform u_color_correction_texture;
u_color_correction_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u_color_correction_texture.binding = 0;
u_color_correction_texture.append_id(default_sampler);
u_color_correction_texture.append_id(p_settings.color_correction_texture);
RID shader = tonemap.shader.version_get_shader(tonemap.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_DISCARD, 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), false, RD::get_singleton()->draw_list_get_current_pass()));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_exposure_texture), 1);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 2, u_glow_texture, u_glow_map), 2);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 3, u_color_correction_texture), 3);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant));
tonemap.push_constant.flags |= p_settings.use_bcs ? TONEMAP_FLAG_USE_BCS : 0;
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.flags |= p_settings.use_glow ? TONEMAP_FLAG_USE_GLOW : 0;
int mode = p_settings.use_1d_color_correction ? TONEMAP_MODE_SUBPASS_1D_LUT : TONEMAP_MODE_SUBPASS;
if (p_settings.view_count > 1) {
// Use USE_MULTIVIEW versions
mode += 6;
}
tonemap.push_constant.tonemapper = p_settings.tonemap_mode;
tonemap.push_constant.flags |= p_settings.use_auto_exposure ? TONEMAP_FLAG_USE_AUTO_EXPOSURE : 0;
tonemap.push_constant.exposure = p_settings.exposure;
tonemap.push_constant.white = p_settings.white;
tonemap.push_constant.auto_exposure_scale = p_settings.auto_exposure_scale;
tonemap.push_constant.flags |= p_settings.use_color_correction ? TONEMAP_FLAG_USE_COLOR_CORRECTION : 0;
tonemap.push_constant.flags |= p_settings.use_debanding ? TONEMAP_FLAG_USE_DEBANDING : 0;
tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier;
tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0;
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RD::Uniform u_source_color;
u_source_color.uniform_type = RD::UNIFORM_TYPE_INPUT_ATTACHMENT;
u_source_color.binding = 0;
u_source_color.append_id(p_source_color);
RD::Uniform u_exposure_texture;
u_exposure_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u_exposure_texture.binding = 0;
u_exposure_texture.append_id(default_sampler);
u_exposure_texture.append_id(p_settings.exposure_texture);
RD::Uniform u_glow_texture;
u_glow_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u_glow_texture.binding = 0;
u_glow_texture.append_id(default_mipmap_sampler);
u_glow_texture.append_id(p_settings.glow_texture);
RD::Uniform u_glow_map;
u_glow_map.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u_glow_map.binding = 1;
u_glow_map.append_id(default_mipmap_sampler);
u_glow_map.append_id(p_settings.glow_map);
RD::Uniform u_color_correction_texture;
u_color_correction_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u_color_correction_texture.binding = 0;
u_color_correction_texture.append_id(default_sampler);
u_color_correction_texture.append_id(p_settings.color_correction_texture);
RID shader = tonemap.shader.version_get_shader(tonemap.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
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, uniform_set_cache->get_cache(shader, 0, u_source_color), 0);
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 1, u_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, uniform_set_cache->get_cache(shader, 2, u_glow_texture, u_glow_map), 2); // should be set to a default texture, it's ignored
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 3, u_color_correction_texture), 3);
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, false, 1u, 3u);
}

View file

@ -0,0 +1,159 @@
/**************************************************************************/
/* tone_mapper.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 TONE_MAPPER_RD_H
#define TONE_MAPPER_RD_H
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/tonemap.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
namespace RendererRD {
class ToneMapper {
private:
enum TonemapMode {
TONEMAP_MODE_NORMAL,
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
};
enum {
TONEMAP_FLAG_USE_BCS = (1 << 0),
TONEMAP_FLAG_USE_GLOW = (1 << 1),
TONEMAP_FLAG_USE_AUTO_EXPOSURE = (1 << 2),
TONEMAP_FLAG_USE_COLOR_CORRECTION = (1 << 3),
TONEMAP_FLAG_USE_FXAA = (1 << 4),
TONEMAP_FLAG_USE_DEBANDING = (1 << 5),
TONEMAP_FLAG_CONVERT_TO_SRGB = (1 << 6),
};
struct TonemapPushConstant {
float bcs[3]; // 12 - 12
uint32_t flags; // 4 - 16
float pixel_size[2]; // 8 - 24
uint32_t tonemapper; // 4 - 28
uint32_t pad; // 4 - 32
uint32_t glow_texture_size[2]; // 8 - 40
float glow_intensity; // 4 - 44
float glow_map_strength; // 4 - 48
uint32_t glow_mode; // 4 - 52
float glow_levels[7]; // 28 - 80
float exposure; // 4 - 84
float white; // 4 - 88
float auto_exposure_scale; // 4 - 92
float luminance_multiplier; // 4 - 96
};
/* tonemap actually writes to a framebuffer, which is
* better to do using the raster pipeline rather than
* compute, as that framebuffer might be in different formats
*/
struct Tonemap {
TonemapPushConstant push_constant;
TonemapShaderRD shader;
RID shader_version;
PipelineCacheRD pipelines[TONEMAP_MODE_MAX];
} tonemap;
public:
ToneMapper();
~ToneMapper();
struct TonemapSettings {
bool use_glow = false;
enum GlowMode {
GLOW_MODE_ADD,
GLOW_MODE_SCREEN,
GLOW_MODE_SOFTLIGHT,
GLOW_MODE_REPLACE,
GLOW_MODE_MIX
};
GlowMode glow_mode = GLOW_MODE_ADD;
float glow_intensity = 1.0;
float glow_map_strength = 0.0f;
float glow_levels[7] = { 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0 };
Vector2i glow_texture_size;
bool glow_use_bicubic_upscale = false;
RID glow_texture;
RID glow_map;
RS::EnvironmentToneMapper tonemap_mode = RS::ENV_TONE_MAPPER_LINEAR;
float exposure = 1.0;
float white = 1.0;
bool use_auto_exposure = false;
float auto_exposure_scale = 0.5;
RID exposure_texture;
float luminance_multiplier = 1.0;
bool use_bcs = false;
float brightness = 1.0;
float contrast = 1.0;
float saturation = 1.0;
bool use_color_correction = false;
bool use_1d_color_correction = false;
RID color_correction_texture;
bool use_fxaa = false;
bool use_debanding = false;
Vector2i texture_size;
uint32_t view_count = 1;
bool convert_to_srgb = false;
};
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);
};
} // namespace RendererRD
#endif // TONE_MAPPER_RD_H

View file

@ -0,0 +1,162 @@
/**************************************************************************/
/* vrs.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "vrs.h"
#include "../renderer_compositor_rd.h"
#include "../storage_rd/texture_storage.h"
#include "../uniform_set_cache_rd.h"
#ifndef _3D_DISABLED
#include "servers/xr_server.h"
#endif // _3D_DISABLED
using namespace RendererRD;
VRS::VRS() {
{
Vector<String> vrs_modes;
vrs_modes.push_back("\n"); // VRS_DEFAULT
vrs_modes.push_back("\n#define USE_MULTIVIEW\n"); // VRS_MULTIVIEW
vrs_shader.shader.initialize(vrs_modes);
if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) {
vrs_shader.shader.set_variant_enabled(VRS_MULTIVIEW, false);
}
vrs_shader.shader_version = vrs_shader.shader.version_create();
//use additive
for (int i = 0; i < VRS_MAX; i++) {
if (vrs_shader.shader.is_variant_enabled(i)) {
vrs_shader.pipelines[i].setup(vrs_shader.shader.version_get_shader(vrs_shader.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
} else {
vrs_shader.pipelines[i].clear();
}
}
}
}
VRS::~VRS() {
vrs_shader.shader.version_free(vrs_shader.shader_version);
}
void VRS::copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multiview) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
// setup our uniforms
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_rd_texture }));
VRSPushConstant push_constant = {};
int mode = p_multiview ? VRS_MULTIVIEW : VRS_DEFAULT;
// Set maximum texel factor based on maximum fragment size, some GPUs do not support 8x8 (fragment shading rate approach).
if (MIN(RD::get_singleton()->limit_get(RD::LIMIT_VRS_MAX_FRAGMENT_WIDTH), RD::get_singleton()->limit_get(RD::LIMIT_VRS_MAX_FRAGMENT_HEIGHT)) > 4) {
push_constant.max_texel_factor = 3.0;
} else {
push_constant.max_texel_factor = 2.0;
}
RID shader = vrs_shader.shader.version_get_shader(vrs_shader.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>());
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, vrs_shader.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, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(VRSPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
Size2i VRS::get_vrs_texture_size(const Size2i p_base_size) const {
int32_t texel_width = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_WIDTH);
int32_t texel_height = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_HEIGHT);
int width = p_base_size.x / texel_width;
if (p_base_size.x % texel_width != 0) {
width++;
}
int height = p_base_size.y / texel_height;
if (p_base_size.y % texel_height != 0) {
height++;
}
return Size2i(width, height);
}
void VRS::update_vrs_texture(RID p_vrs_fb, RID p_render_target) {
TextureStorage *texture_storage = TextureStorage::get_singleton();
RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(p_render_target);
RS::ViewportVRSUpdateMode vrs_update_mode = texture_storage->render_target_get_vrs_update_mode(p_render_target);
if (vrs_mode != RS::VIEWPORT_VRS_DISABLED && vrs_update_mode != RS::VIEWPORT_VRS_UPDATE_DISABLED) {
RD::get_singleton()->draw_command_begin_label("VRS Setup");
if (vrs_mode == RS::VIEWPORT_VRS_TEXTURE) {
RID vrs_texture = texture_storage->render_target_get_vrs_texture(p_render_target);
if (vrs_texture.is_valid()) {
RID rd_texture = texture_storage->texture_get_rd_texture(vrs_texture);
int layers = texture_storage->texture_get_layers(vrs_texture);
if (rd_texture.is_valid()) {
// Copy into our density buffer
copy_vrs(rd_texture, p_vrs_fb, layers > 1);
}
}
#ifndef _3D_DISABLED
} else if (vrs_mode == RS::VIEWPORT_VRS_XR) {
Ref<XRInterface> interface = XRServer::get_singleton()->get_primary_interface();
if (interface.is_valid()) {
RID vrs_texture = interface->get_vrs_texture();
if (vrs_texture.is_valid()) {
RID rd_texture = texture_storage->texture_get_rd_texture(vrs_texture);
int layers = texture_storage->texture_get_layers(vrs_texture);
if (rd_texture.is_valid()) {
// Copy into our density buffer
copy_vrs(rd_texture, p_vrs_fb, layers > 1);
}
}
}
#endif // _3D_DISABLED
}
if (vrs_update_mode == RS::VIEWPORT_VRS_UPDATE_ONCE) {
texture_storage->render_target_set_vrs_update_mode(p_render_target, RS::VIEWPORT_VRS_UPDATE_DISABLED);
}
RD::get_singleton()->draw_command_end_label();
}
}

View file

@ -0,0 +1,76 @@
/**************************************************************************/
/* vrs.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 VRS_RD_H
#define VRS_RD_H
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/vrs.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
namespace RendererRD {
class VRS {
private:
enum VRSMode {
VRS_DEFAULT,
VRS_MULTIVIEW,
VRS_MAX,
};
struct VRSPushConstant {
float max_texel_factor; // 4x8, 8x4 and 8x8 are only available on some GPUs.
float res1;
float res2;
float res3;
};
struct VRSShader {
// VRSPushConstant push_constant;
VrsShaderRD shader;
RID shader_version;
PipelineCacheRD pipelines[VRS_MAX];
} vrs_shader;
public:
VRS();
~VRS();
void copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multiview = false);
Size2i get_vrs_texture_size(const Size2i p_base_size) const;
void update_vrs_texture(RID p_vrs_fb, RID p_render_target);
};
} // namespace RendererRD
#endif // VRS_RD_H

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
Import("env")
env.add_source_files(env.servers_sources, "*.cpp")

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,359 @@
/**************************************************************************/
/* fog.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 FOG_RD_H
#define FOG_RD_H
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "servers/rendering/environment/renderer_fog.h"
#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
#include "servers/rendering/renderer_rd/environment/gi.h"
#include "servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h"
#include "servers/rendering/storage/utilities.h"
#define RB_SCOPE_FOG SNAME("Fog")
namespace RendererRD {
class Fog : public RendererFog {
private:
static Fog *singleton;
/* FOG VOLUMES */
struct FogVolume {
RID material;
Vector3 size = Vector3(2, 2, 2);
RS::FogVolumeShape shape = RS::FOG_VOLUME_SHAPE_BOX;
Dependency dependency;
};
mutable RID_Owner<FogVolume, true> fog_volume_owner;
struct FogVolumeInstance {
RID volume;
Transform3D transform;
bool active = false;
};
mutable RID_Owner<FogVolumeInstance> fog_volume_instance_owner;
const int SAMPLERS_BINDING_FIRST_INDEX = 3;
/* Volumetric Fog */
struct VolumetricFogShader {
enum FogSet {
FOG_SET_BASE,
FOG_SET_UNIFORMS,
FOG_SET_MATERIAL,
FOG_SET_MAX,
};
struct FogPushConstant {
float position[3];
float pad;
float size[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];
};
ShaderCompiler compiler;
VolumetricFogShaderRD shader;
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 base_emission[3];
float base_density;
float base_scattering[3];
float phase_g;
float detail_spread;
float gi_inject;
uint32_t max_voxel_gi_instances;
uint32_t cluster_type_size;
float screen_size[2];
uint32_t cluster_shift;
uint32_t cluster_width;
uint32_t max_cluster_element_count_div_32;
uint32_t use_temporal_reprojection;
uint32_t temporal_frame;
float temporal_blend;
float cam_rotation[12];
float to_prev_view[16];
float radiance_inverse_xform[12];
};
VolumetricFogProcessShaderRD process_shader;
RID process_shader_version;
RID process_pipelines[VOLUMETRIC_FOG_PROCESS_SHADER_MAX];
} volumetric_fog;
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);
struct FogShaderData : public RendererRD::MaterialStorage::ShaderData {
bool valid = false;
RID version;
RID pipeline;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size = 0;
String code;
bool uses_time = false;
virtual void set_code(const String &p_Code);
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
FogShaderData() {}
virtual ~FogShaderData();
};
struct FogMaterialData : public RendererRD::MaterialStorage::MaterialData {
FogShaderData *shader_data = nullptr;
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 HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual ~FogMaterialData();
};
RendererRD::MaterialStorage::ShaderData *_create_fog_shader_func();
static RendererRD::MaterialStorage::ShaderData *_create_fog_shader_funcs();
RendererRD::MaterialStorage::MaterialData *_create_fog_material_func(FogShaderData *p_shader);
static RendererRD::MaterialStorage::MaterialData *_create_fog_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader);
public:
static Fog *get_singleton() { return singleton; }
Fog();
~Fog();
/* FOG VOLUMES */
bool owns_fog_volume(RID p_rid) { return fog_volume_owner.owns(p_rid); };
virtual RID fog_volume_allocate() override;
virtual void fog_volume_initialize(RID p_rid) override;
virtual void fog_volume_free(RID p_rid) override;
Dependency *fog_volume_get_dependency(RID p_fog_volume) const;
virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override;
virtual void fog_volume_set_size(RID p_fog_volume, const Vector3 &p_size) override;
virtual void fog_volume_set_material(RID p_fog_volume, RID p_material) override;
virtual RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const override;
RID fog_volume_get_material(RID p_fog_volume) const;
virtual AABB fog_volume_get_aabb(RID p_fog_volume) const override;
Vector3 fog_volume_get_size(RID p_fog_volume) const;
/* FOG VOLUMES INSTANCE */
bool owns_fog_volume_instance(RID p_rid) { return fog_volume_instance_owner.owns(p_rid); };
RID fog_volume_instance_create(RID p_fog_volume);
void fog_instance_free(RID p_rid);
void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) {
Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
ERR_FAIL_NULL(fvi);
fvi->transform = p_transform;
}
void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) {
Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
ERR_FAIL_NULL(fvi);
fvi->active = p_active;
}
RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const {
Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
ERR_FAIL_NULL_V(fvi, RID());
return fvi->volume;
}
Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const {
Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
ERR_FAIL_NULL_V(fvi, Vector3());
return fvi->transform.get_origin();
}
/* Volumetric FOG */
class VolumetricFog : public RenderBufferCustomDataRD {
GDCLASS(VolumetricFog, RenderBufferCustomDataRD)
public:
enum {
MAX_TEMPORAL_FRAMES = 16
};
uint32_t width = 0;
uint32_t height = 0;
uint32_t depth = 0;
float length;
float spread;
RID light_density_map;
RID prev_light_density_map;
RID fog_map;
RID density_map;
RID light_map;
RID emissive_map;
RID fog_uniform_set;
RID copy_uniform_set;
struct {
RID process_uniform_set_density;
RID process_uniform_set;
RID process_uniform_set2;
} gi_dependent_sets;
RID sdfgi_uniform_set;
RID sky_uniform_set;
int last_shadow_filter = -1;
virtual void configure(RenderSceneBuffersRD *p_render_buffers) override{};
virtual void free_data() override{};
bool sync_gi_dependent_sets_validity(bool p_ensure_freed = false);
void init(const Vector3i &fog_size, RID p_sky_shader);
~VolumetricFog();
};
void init_fog_shader(uint32_t p_max_directional_lights, int p_roughness_layers, bool p_is_using_radiance_cubemap_array);
void free_fog_shader();
struct VolumetricFogSettings {
Vector2i rb_size;
double time;
bool is_using_radiance_cubemap_array;
uint32_t max_cluster_elements;
bool volumetric_fog_filter_active;
RID shadow_sampler;
RID voxel_gi_buffer;
RID shadow_atlas_depth;
RID omni_light_buffer;
RID spot_light_buffer;
RID directional_shadow_depth;
RID directional_light_buffer;
// Objects related to our render buffer
Ref<VolumetricFog> vfog;
ClusterBuilderRD *cluster_builder;
GI *gi;
Ref<GI::SDFGI> sdfgi;
Ref<GI::RenderBuffersGI> rbgi;
RID env;
SkyRD *sky;
};
void volumetric_fog_update(const VolumetricFogSettings &p_settings, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_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);
};
} // namespace RendererRD
#endif // FOG_RD_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,833 @@
/**************************************************************************/
/* gi.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 GI_RD_H
#define GI_RD_H
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "servers/rendering/environment/renderer_gi.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_rd/environment/sky.h"
#include "servers/rendering/renderer_rd/shaders/environment/gi.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/environment/sdfgi_debug_probes.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/environment/voxel_gi.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/environment/voxel_gi_debug.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
#include "servers/rendering/storage/utilities.h"
#define RB_SCOPE_GI SNAME("rbgi")
#define RB_SCOPE_SDFGI SNAME("sdfgi")
#define RB_TEX_AMBIENT SNAME("ambient")
#define RB_TEX_REFLECTION SNAME("reflection")
// Forward declare RenderDataRD and RendererSceneRenderRD so we can pass it into some of our methods, these classes are pretty tightly bound
class RenderDataRD;
class RendererSceneRenderRD;
namespace RendererRD {
class GI : public RendererGI {
public:
/* VOXEL GI STORAGE */
struct VoxelGI {
RID octree_buffer;
RID data_buffer;
RID sdf_texture;
uint32_t octree_buffer_size = 0;
uint32_t data_buffer_size = 0;
Vector<int> level_counts;
int cell_count = 0;
Transform3D to_cell_xform;
AABB bounds;
Vector3i octree_size;
float dynamic_range = 2.0;
float energy = 1.0;
float baked_exposure = 1.0;
float bias = 1.4;
float normal_bias = 0.0;
float propagation = 0.5;
bool interior = false;
bool use_two_bounces = true;
uint32_t version = 1;
uint32_t data_version = 1;
Dependency dependency;
};
/* VOXEL_GI INSTANCE */
//@TODO VoxelGIInstance is still directly used in the render code, we'll address this when we refactor the render code itself.
struct VoxelGIInstance {
// access to our containers
GI *gi = nullptr;
RID probe;
RID texture;
RID write_buffer;
struct Mipmap {
RID texture;
RID uniform_set;
RID second_bounce_uniform_set;
RID write_uniform_set;
uint32_t level;
uint32_t cell_offset;
uint32_t cell_count;
};
Vector<Mipmap> mipmaps;
struct DynamicMap {
RID texture; //color normally, or emission on first pass
RID fb_depth; //actual depth buffer for the first pass, float depth for later passes
RID depth; //actual depth buffer for the first pass, float depth for later passes
RID normal; //normal buffer for the first pass
RID albedo; //emission buffer for the first pass
RID orm; //orm buffer for the first pass
RID fb; //used for rendering, only valid on first map
RID uniform_set;
uint32_t size;
int mipmap; // mipmap to write to, -1 if no mipmap assigned
};
Vector<DynamicMap> dynamic_maps;
int slot = -1;
uint32_t last_probe_version = 0;
uint32_t last_probe_data_version = 0;
//uint64_t last_pass = 0;
uint32_t render_index = 0;
bool has_dynamic_object_data = false;
Transform3D transform;
void update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects);
void debug(RD::DrawListID p_draw_list, RID p_framebuffer, const Projection &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
void free_resources();
};
private:
static GI *singleton;
/* VOXEL GI STORAGE */
mutable RID_Owner<VoxelGI, true> voxel_gi_owner;
/* VOXEL_GI INSTANCE */
mutable RID_Owner<VoxelGIInstance> voxel_gi_instance_owner;
struct VoxelGILight {
uint32_t type;
float energy;
float radius;
float attenuation;
float color[3];
float cos_spot_angle;
float position[3];
float inv_spot_attenuation;
float direction[3];
uint32_t has_shadow;
};
struct VoxelGIPushConstant {
int32_t limits[3];
uint32_t stack_size;
float emission_scale;
float propagation;
float dynamic_range;
uint32_t light_count;
uint32_t cell_offset;
uint32_t cell_count;
float aniso_strength;
uint32_t pad;
};
struct VoxelGIDynamicPushConstant {
int32_t limits[3];
uint32_t light_count;
int32_t x_dir[3];
float z_base;
int32_t y_dir[3];
float z_sign;
int32_t z_dir[3];
float pos_multiplier;
uint32_t rect_pos[2];
uint32_t rect_size[2];
uint32_t prev_rect_ofs[2];
uint32_t prev_rect_size[2];
uint32_t flip_x;
uint32_t flip_y;
float dynamic_range;
uint32_t on_mipmap;
float propagation;
float pad[3];
};
VoxelGILight *voxel_gi_lights = nullptr;
uint32_t voxel_gi_max_lights = 32;
RID voxel_gi_lights_uniform;
enum {
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
};
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 {
VOXEL_GI_DEBUG_COLOR,
VOXEL_GI_DEBUG_LIGHT,
VOXEL_GI_DEBUG_EMISSION,
VOXEL_GI_DEBUG_LIGHT_FULL,
VOXEL_GI_DEBUG_MAX
};
struct VoxelGIDebugPushConstant {
float projection[16];
uint32_t cell_offset;
float dynamic_range;
float alpha;
uint32_t level;
int32_t bounds[3];
uint32_t pad;
};
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 */
struct SDFGIShader {
enum SDFGIPreprocessShaderVersion {
PRE_PROCESS_SCROLL,
PRE_PROCESS_SCROLL_OCCLUSION,
PRE_PROCESS_JUMP_FLOOD_INITIALIZE,
PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF,
PRE_PROCESS_JUMP_FLOOD,
PRE_PROCESS_JUMP_FLOOD_OPTIMIZED,
PRE_PROCESS_JUMP_FLOOD_UPSCALE,
PRE_PROCESS_OCCLUSION,
PRE_PROCESS_STORE,
PRE_PROCESS_MAX
};
struct PreprocessPushConstant {
int32_t scroll[3];
int32_t grid_size;
int32_t probe_offset[3];
int32_t step_size;
int32_t half_size;
uint32_t occlusion_index;
int32_t cascade;
uint32_t pad;
};
SdfgiPreprocessShaderRD preprocess;
RID preprocess_shader;
RID preprocess_pipeline[PRE_PROCESS_MAX];
struct DebugPushConstant {
float grid_size[3];
uint32_t max_cascades;
int32_t screen_size[2];
float y_mult;
float z_near;
float inv_projection[3][4];
float cam_basis[3][3];
float cam_origin[3];
};
SdfgiDebugShaderRD debug;
RID debug_shader;
RID debug_shader_version;
RID debug_pipeline;
enum ProbeDebugMode {
PROBE_DEBUG_PROBES,
PROBE_DEBUG_PROBES_MULTIVIEW,
PROBE_DEBUG_VISIBILITY,
PROBE_DEBUG_VISIBILITY_MULTIVIEW,
PROBE_DEBUG_MAX
};
struct DebugProbesSceneData {
float projection[2][16];
};
struct DebugProbesPushConstant {
uint32_t band_power;
uint32_t sections_in_band;
uint32_t band_mask;
float section_arc;
float grid_size[3];
uint32_t cascade;
uint32_t pad;
float y_mult;
int32_t probe_debug_index;
int32_t probe_axis_size;
};
SdfgiDebugProbesShaderRD debug_probes;
RID debug_probes_shader;
RID debug_probes_shader_version;
PipelineCacheRD debug_probes_pipeline[PROBE_DEBUG_MAX];
struct Light {
float color[3];
float energy;
float direction[3];
uint32_t has_shadow;
float position[3];
float attenuation;
uint32_t type;
float cos_spot_angle;
float inv_spot_attenuation;
float radius;
};
struct DirectLightPushConstant {
float grid_size[3];
uint32_t max_cascades;
uint32_t cascade;
uint32_t light_count;
uint32_t process_offset;
uint32_t process_increment;
int32_t probe_axis_size;
float bounce_feedback;
float y_mult;
uint32_t use_occlusion;
};
enum {
DIRECT_LIGHT_MODE_STATIC,
DIRECT_LIGHT_MODE_DYNAMIC,
DIRECT_LIGHT_MODE_MAX
};
SdfgiDirectLightShaderRD direct_light;
RID direct_light_shader;
RID direct_light_pipeline[DIRECT_LIGHT_MODE_MAX];
enum {
INTEGRATE_MODE_PROCESS,
INTEGRATE_MODE_STORE,
INTEGRATE_MODE_SCROLL,
INTEGRATE_MODE_SCROLL_STORE,
INTEGRATE_MODE_MAX
};
struct IntegratePushConstant {
enum {
SKY_MODE_DISABLED,
SKY_MODE_COLOR,
SKY_MODE_SKY,
};
float grid_size[3];
uint32_t max_cascades;
uint32_t probe_axis_size;
uint32_t cascade;
uint32_t history_index;
uint32_t history_size;
uint32_t ray_count;
float ray_bias;
int32_t image_size[2];
int32_t world_offset[3];
uint32_t sky_mode;
int32_t scroll[3];
float sky_energy;
float sky_color[3];
float y_mult;
uint32_t store_ambient_texture;
uint32_t pad[3];
};
SdfgiIntegrateShaderRD integrate;
RID integrate_shader;
RID integrate_pipeline[INTEGRATE_MODE_MAX];
RID integrate_default_sky_uniform_set;
} sdfgi_shader;
public:
static GI *get_singleton() { return singleton; }
/* GI */
enum {
MAX_VOXEL_GI_INSTANCES = 8
};
// Struct for use in render buffer
class RenderBuffersGI : public RenderBufferCustomDataRD {
GDCLASS(RenderBuffersGI, RenderBufferCustomDataRD)
private:
RID voxel_gi_buffer;
public:
RID voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
RID full_buffer;
RID full_dispatch;
RID full_mask;
/* GI buffers */
bool using_half_size_gi = false;
RID uniform_set[RendererSceneRender::MAX_RENDER_VIEWS];
RID scene_data_ubo;
RID get_voxel_gi_buffer();
virtual void configure(RenderSceneBuffersRD *p_render_buffers) override{};
virtual void free_data() override;
};
/* VOXEL GI API */
bool owns_voxel_gi(RID p_rid) { return voxel_gi_owner.owns(p_rid); };
virtual RID voxel_gi_allocate() override;
virtual void voxel_gi_free(RID p_voxel_gi) override;
virtual void voxel_gi_initialize(RID p_voxel_gi) override;
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) override;
virtual AABB voxel_gi_get_bounds(RID p_voxel_gi) const override;
virtual Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const override;
virtual Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const override;
virtual Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const override;
virtual Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const override;
virtual Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const override;
virtual Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const override;
virtual void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) override;
virtual float voxel_gi_get_dynamic_range(RID p_voxel_gi) const override;
virtual void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) override;
virtual float voxel_gi_get_propagation(RID p_voxel_gi) const override;
virtual void voxel_gi_set_energy(RID p_voxel_gi, float p_energy) override;
virtual float voxel_gi_get_energy(RID p_voxel_gi) const override;
virtual void voxel_gi_set_baked_exposure_normalization(RID p_voxel_gi, float p_baked_exposure) override;
virtual float voxel_gi_get_baked_exposure_normalization(RID p_voxel_gi) const override;
virtual void voxel_gi_set_bias(RID p_voxel_gi, float p_bias) override;
virtual float voxel_gi_get_bias(RID p_voxel_gi) const override;
virtual void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) override;
virtual float voxel_gi_get_normal_bias(RID p_voxel_gi) const override;
virtual void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) override;
virtual bool voxel_gi_is_interior(RID p_voxel_gi) const override;
virtual void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) override;
virtual bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const override;
virtual uint32_t voxel_gi_get_version(RID p_probe) const override;
uint32_t voxel_gi_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 voxel_gi_get_sdf_texture(RID p_voxel_gi);
Dependency *voxel_gi_get_dependency(RID p_voxel_gi) const;
/* VOXEL_GI INSTANCE */
_FORCE_INLINE_ RID voxel_gi_instance_get_texture(RID p_probe) {
VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
ERR_FAIL_NULL_V(voxel_gi, RID());
return voxel_gi->texture;
};
_FORCE_INLINE_ void voxel_gi_instance_set_render_index(RID p_probe, uint32_t p_index) {
VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
ERR_FAIL_NULL(voxel_gi);
voxel_gi->render_index = p_index;
};
bool voxel_gi_instance_owns(RID p_rid) const {
return voxel_gi_instance_owner.owns(p_rid);
}
void voxel_gi_instance_free(RID p_rid);
RS::VoxelGIQuality voxel_gi_quality = RS::VOXEL_GI_QUALITY_LOW;
/* SDFGI */
class SDFGI : public RenderBufferCustomDataRD {
GDCLASS(SDFGI, RenderBufferCustomDataRD)
public:
enum {
MAX_CASCADES = 8,
CASCADE_SIZE = 128,
PROBE_DIVISOR = 16,
ANISOTROPY_SIZE = 6,
MAX_DYNAMIC_LIGHTS = 128,
MAX_STATIC_LIGHTS = 1024,
LIGHTPROBE_OCT_SIZE = 6,
SH_SIZE = 16
};
struct Cascade {
struct UBO {
float offset[3];
float to_cell;
int32_t probe_offset[3];
uint32_t pad;
float pad2[4];
};
//cascade blocks are full-size for volume (128^3), half size for albedo/emission
RID sdf_tex;
RID light_tex;
RID light_aniso_0_tex;
RID light_aniso_1_tex;
RID light_data;
RID light_aniso_0_data;
RID light_aniso_1_data;
struct SolidCell { // this struct is unused, but remains as reference for size
uint32_t position;
uint32_t albedo;
uint32_t static_light;
uint32_t static_light_aniso;
};
// Buffers for indirect compute dispatch.
RID solid_cell_dispatch_buffer_storage;
RID solid_cell_dispatch_buffer_call;
RID solid_cell_buffer;
RID lightprobe_history_tex;
RID lightprobe_average_tex;
float cell_size;
Vector3i position;
static const Vector3i DIRTY_ALL;
Vector3i dirty_regions; //(0,0,0 is not dirty, negative is refresh from the end, DIRTY_ALL is refresh all.
RID sdf_store_uniform_set;
RID sdf_direct_light_static_uniform_set;
RID sdf_direct_light_dynamic_uniform_set;
RID scroll_uniform_set;
RID scroll_occlusion_uniform_set;
RID integrate_uniform_set;
RID lights_buffer;
float baked_exposure_normalization = 1.0;
bool all_dynamic_lights_dirty = true;
};
// access to our containers
GI *gi = nullptr;
// used for rendering (voxelization)
RID render_albedo;
RID render_emission;
RID render_emission_aniso;
RID render_occlusion[8];
RID render_geom_facing;
RID render_sdf[2];
RID render_sdf_half[2];
// used for ping pong processing in cascades
RID sdf_initialize_uniform_set;
RID sdf_initialize_half_uniform_set;
RID jump_flood_uniform_set[2];
RID jump_flood_half_uniform_set[2];
RID sdf_upscale_uniform_set;
int upscale_jfa_uniform_set_index;
RID occlusion_uniform_set;
uint32_t cascade_size = 128;
LocalVector<Cascade> cascades;
RID lightprobe_texture;
RID lightprobe_data;
RID occlusion_texture;
RID occlusion_data;
RID ambient_texture; //integrates with volumetric fog
RID lightprobe_history_scroll; //used for scrolling lightprobes
RID lightprobe_average_scroll; //used for scrolling lightprobes
uint32_t history_size = 0;
float solid_cell_ratio = 0;
uint32_t solid_cell_count = 0;
int num_cascades = 6;
float min_cell_size = 0;
uint32_t probe_axis_count = 0; //amount of probes per axis, this is an odd number because it encloses endpoints
RID debug_uniform_set[RendererSceneRender::MAX_RENDER_VIEWS];
RID debug_probes_scene_data_ubo;
RID debug_probes_uniform_set;
RID cascades_ubo;
bool uses_occlusion = false;
float bounce_feedback = 0.5;
bool reads_sky = true;
float energy = 1.0;
float normal_bias = 1.1;
float probe_bias = 1.1;
RS::EnvironmentSDFGIYScale y_scale_mode = RS::ENV_SDFGI_Y_SCALE_75_PERCENT;
float y_mult = 1.0;
uint32_t version = 0;
uint32_t render_pass = 0;
int32_t cascade_dynamic_light_count[SDFGI::MAX_CASCADES]; //used dynamically
RID integrate_sky_uniform_set;
virtual void configure(RenderSceneBuffersRD *p_render_buffers) override{};
virtual void free_data() override;
~SDFGI();
void create(RID p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size, GI *p_gi);
void update(RID p_env, const Vector3 &p_world_position);
void update_light();
void update_probes(RID p_env, RendererRD::SkyRD::Sky *p_sky);
void store_probes();
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(uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture, const Vector<RID> &p_texture_views);
void debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms);
void pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data);
void render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, float p_exposure_normalization);
void render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result);
};
RS::EnvironmentSDFGIRayCount sdfgi_ray_count = RS::ENV_SDFGI_RAY_COUNT_16;
RS::EnvironmentSDFGIFramesToConverge sdfgi_frames_to_converge = RS::ENV_SDFGI_CONVERGE_IN_30_FRAMES;
RS::EnvironmentSDFGIFramesToUpdateLight sdfgi_frames_to_update_light = RS::ENV_SDFGI_UPDATE_LIGHT_IN_4_FRAMES;
float sdfgi_solid_cell_ratio = 0.25;
Vector3 sdfgi_debug_probe_pos;
Vector3 sdfgi_debug_probe_dir;
bool sdfgi_debug_probe_enabled = false;
Vector3i sdfgi_debug_probe_index;
uint32_t sdfgi_current_version = 0;
/* SDFGI UPDATE */
int sdfgi_get_lightprobe_octahedron_size() const { return SDFGI::LIGHTPROBE_OCT_SIZE; }
virtual void sdfgi_reset() override;
struct SDFGIData {
float grid_size[3];
uint32_t max_cascades;
uint32_t use_occlusion;
int32_t probe_axis_size;
float probe_to_uvw;
float normal_bias;
float lightprobe_tex_pixel_size[3];
float energy;
float lightprobe_uv_offset[3];
float y_mult;
float occlusion_clamp[3];
uint32_t pad3;
float occlusion_renormalize[3];
uint32_t pad4;
float cascade_probe_size[3];
uint32_t pad5;
struct ProbeCascadeData {
float position[3]; //offset of (0,0,0) in world coordinates
float to_probe; // 1/bounds * grid_size
int32_t probe_world_offset[3];
float to_cell; // 1/bounds * grid_size
float pad[3];
float exposure_normalization;
};
ProbeCascadeData cascades[SDFGI::MAX_CASCADES];
};
struct VoxelGIData {
float xform[16]; // 64 - 64
float bounds[3]; // 12 - 76
float dynamic_range; // 4 - 80
float bias; // 4 - 84
float normal_bias; // 4 - 88
uint32_t blend_ambient; // 4 - 92
uint32_t mipmaps; // 4 - 96
float pad[3]; // 12 - 108
float exposure_normalization; // 4 - 112
};
struct SceneData {
float inv_projection[2][16];
float cam_transform[16];
float eye_offset[2][4];
int32_t screen_size[2];
float pad1;
float pad2;
};
struct PushConstant {
uint32_t max_voxel_gi_instances;
uint32_t high_quality_vct;
uint32_t orthogonal;
uint32_t view_index;
float proj_info[4];
float z_near;
float z_far;
float pad2;
float pad3;
};
RID sdfgi_ubo;
enum Mode {
MODE_VOXEL_GI,
MODE_SDFGI,
MODE_COMBINED,
MODE_MAX
};
enum ShaderSpecializations {
SHADER_SPECIALIZATION_HALF_RES = 1 << 0,
SHADER_SPECIALIZATION_USE_FULL_PROJECTION_MATRIX = 1 << 1,
SHADER_SPECIALIZATION_USE_VRS = 1 << 2,
SHADER_SPECIALIZATION_VARIATIONS = 8,
};
RID default_voxel_gi_buffer;
bool half_resolution = false;
GiShaderRD shader;
RID shader_version;
RID pipelines[SHADER_SPECIALIZATION_VARIATIONS][MODE_MAX];
GI();
~GI();
void init(RendererRD::SkyRD *p_sky);
void free();
Ref<SDFGI> create_sdfgi(RID p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size);
void setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used);
void process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, RID p_environment, uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances);
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<RenderGeometryInstance *> &p_dynamic_objects);
void debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const Projection &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
};
} // namespace RendererRD
#endif // GI_RD_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,321 @@
/**************************************************************************/
/* sky.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 SKY_RD_H
#define SKY_RD_H
#include "core/templates/rid_owner.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/environment/sky.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
#include "servers/rendering/shader_compiler.h"
// Forward declare RendererSceneRenderRD so we can pass it into some of our methods, these classes are pretty tightly bound
class RendererSceneRenderRD;
class RenderSceneBuffersRD;
namespace RendererRD {
class SkyRD {
public:
enum SkySet {
SKY_SET_UNIFORMS,
SKY_SET_MATERIAL,
SKY_SET_TEXTURES,
SKY_SET_FOG,
};
const int SAMPLERS_BINDING_FIRST_INDEX = 4;
// 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:
RD::DataFormat texture_format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
enum SkyTextureSetVersion {
SKY_TEXTURE_SET_BACKGROUND,
SKY_TEXTURE_SET_HALF_RES,
SKY_TEXTURE_SET_QUARTER_RES,
SKY_TEXTURE_SET_CUBEMAP,
SKY_TEXTURE_SET_CUBEMAP_HALF_RES,
SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES,
SKY_TEXTURE_SET_MAX
};
enum SkyVersion {
SKY_VERSION_BACKGROUND,
SKY_VERSION_HALF_RES,
SKY_VERSION_QUARTER_RES,
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
};
struct SkyPushConstant {
float orientation[12]; // 48 - 48
float projection[4]; // 16 - 64
float position[3]; // 12 - 76
float time; // 4 - 80
float pad[3]; // 12 - 92
float luminance_multiplier; // 4 - 96
// 128 is the max size of a push constant. We can replace "pad" but we can't add any more.
};
struct SkyShaderData : public RendererRD::MaterialStorage::ShaderData {
bool valid = false;
RID version;
PipelineCacheRD pipelines[SKY_VERSION_MAX];
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size = 0;
String code;
bool uses_time = false;
bool uses_position = false;
bool uses_half_res = false;
bool uses_quarter_res = false;
bool uses_light = false;
virtual void set_code(const String &p_Code);
virtual bool is_animated() const;
virtual bool casts_shadows() 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, const Projection &p_projection, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier);
public:
struct SkySceneState {
struct UBO {
float combined_reprojection[RendererSceneRender::MAX_RENDER_VIEWS][16]; // 2 x 64 - 128
float view_inv_projections[RendererSceneRender::MAX_RENDER_VIEWS][16]; // 2 x 64 - 256
float view_eye_offsets[RendererSceneRender::MAX_RENDER_VIEWS][4]; // 2 x 16 - 288
uint32_t volumetric_fog_enabled; // 4 - 292
float volumetric_fog_inv_length; // 4 - 296
float volumetric_fog_detail_spread; // 4 - 300
float volumetric_fog_sky_affect; // 4 - 304
uint32_t fog_enabled; // 4 - 308
float fog_sky_affect; // 4 - 312
float fog_density; // 4 - 316
float fog_sun_scatter; // 4 - 320
float fog_light_color[3]; // 12 - 332
float fog_aerial_perspective; // 4 - 336
float z_far; // 4 - 340
uint32_t directional_light_count; // 4 - 344
uint32_t pad1; // 4 - 348
uint32_t pad2; // 4 - 352
};
UBO ubo;
uint32_t view_count = 1;
Transform3D cam_transform;
Projection cam_projection;
SkyDirectionalLightData *directional_lights = nullptr;
SkyDirectionalLightData *last_frame_directional_lights = nullptr;
uint32_t max_directional_lights;
uint32_t last_frame_directional_light_count;
RID directional_light_buffer;
RID uniform_set;
RID uniform_buffer;
RID fog_uniform_set;
RID default_fog_uniform_set;
RID fog_shader;
RID fog_material;
RID fog_only_texture_uniform_set;
} sky_scene_state;
struct ReflectionData {
struct Layer {
struct Mipmap {
RID framebuffers[6];
RID views[6];
Size2i size;
};
Vector<Mipmap> mipmaps; //per-face view
Vector<RID> views; // per-cubemap view
};
struct DownsampleLayer {
struct Mipmap {
RID view;
Size2i size;
// for mobile only
RID views[6];
RID framebuffers[6];
};
Vector<Mipmap> mipmaps;
};
RID radiance_base_cubemap; //cubemap for first layer, first cubemap
RID downsampled_radiance_cubemap;
DownsampleLayer downsampled_layer;
RID coefficient_buffer;
bool dirty = true;
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, RD::DataFormat p_texture_format);
void create_reflection_fast_filter(bool p_use_arrays);
void create_reflection_importance_sample(bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality);
void update_reflection_mipmaps(int p_start, int p_end);
};
/* Sky shader */
struct SkyShader {
SkyShaderRD shader;
ShaderCompiler compiler;
RID default_shader;
RID default_material;
RID default_shader_rd;
} sky_shader;
struct SkyMaterialData : public RendererRD::MaterialStorage::MaterialData {
SkyShaderData *shader_data = nullptr;
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 HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual ~SkyMaterialData();
};
struct Sky {
RID radiance;
RID quarter_res_pass;
RID quarter_res_framebuffer;
Size2i screen_size;
RID uniform_set;
RID material;
RID uniform_buffer;
int radiance_size = 256;
RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC;
ReflectionData reflection;
bool dirty = false;
int processing_layer = 0;
Sky *dirty_list = nullptr;
float baked_exposure = 1.0;
//State to track when radiance cubemap needs updating
SkyMaterialData *prev_material = nullptr;
Vector3 prev_position;
float prev_time;
void free();
RID get_textures(SkyTextureSetVersion p_version, RID p_default_shader_rd, Ref<RenderSceneBuffersRD> p_render_buffers);
bool set_radiance_size(int p_radiance_size);
bool set_mode(RS::SkyMode p_mode);
bool set_material(RID p_material);
Ref<Image> bake_panorama(float p_energy, int p_roughness_layers, const Size2i &p_size);
};
uint32_t sky_ggx_samples_quality;
bool sky_use_cubemap_array;
Sky *dirty_sky_list = nullptr;
mutable RID_Owner<Sky, true> sky_owner;
int roughness_layers;
RendererRD::MaterialStorage::ShaderData *_create_sky_shader_func();
static RendererRD::MaterialStorage::ShaderData *_create_sky_shader_funcs();
RendererRD::MaterialStorage::MaterialData *_create_sky_material_func(SkyShaderData *p_shader);
static RendererRD::MaterialStorage::MaterialData *_create_sky_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader);
SkyRD();
void init();
void set_texture_format(RD::DataFormat p_texture_format);
~SkyRD();
void setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, uint32_t p_view_count, const Projection *p_view_projections, const Vector3 *p_view_eye_offsets, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const Size2i p_screen_size, Vector2 p_jitter, RendererSceneRenderRD *p_scene_render);
void update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, const Vector3 &p_global_pos, double p_time, float p_luminance_multiplier = 1.0);
void update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, double p_time, float p_luminance_multiplier = 1.0);
void draw_sky(RD::DrawListID p_draw_list, Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, RID p_fb, double p_time, float p_luminance_multiplier = 1.0);
void invalidate_sky(Sky *p_sky);
void update_dirty_skys();
RID sky_get_material(RID p_sky) const;
RID sky_get_radiance_texture_rd(RID p_sky) const;
float sky_get_baked_exposure(RID p_sky) const;
RID allocate_sky_rid();
void initialize_sky_rid(RID p_rid);
Sky *get_sky(RID p_sky) const;
void free_sky(RID p_sky);
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);
};
} // namespace RendererRD
#endif // SKY_RD_H

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
Import("env")
env.add_source_files(env.servers_sources, "*.cpp")

View file

@ -0,0 +1,671 @@
/**************************************************************************/
/* render_forward_clustered.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 RENDER_FORWARD_CLUSTERED_H
#define RENDER_FORWARD_CLUSTERED_H
#include "core/templates/paged_allocator.h"
#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
#include "servers/rendering/renderer_rd/effects/fsr2.h"
#include "servers/rendering/renderer_rd/effects/resolve.h"
#include "servers/rendering/renderer_rd/effects/ss_effects.h"
#include "servers/rendering/renderer_rd/effects/taa.h"
#include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
#include "servers/rendering/renderer_rd/shaders/forward_clustered/best_fit_normal.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/utilities.h"
#define RB_SCOPE_FORWARD_CLUSTERED SNAME("forward_clustered")
#define RB_TEX_SPECULAR SNAME("specular")
#define RB_TEX_SPECULAR_MSAA SNAME("specular_msaa")
#define RB_TEX_NORMAL_ROUGHNESS SNAME("normal_roughness")
#define RB_TEX_NORMAL_ROUGHNESS_MSAA SNAME("normal_roughness_msaa")
#define RB_TEX_VOXEL_GI SNAME("voxel_gi")
#define RB_TEX_VOXEL_GI_MSAA SNAME("voxel_gi_msaa")
namespace RendererSceneRenderImplementation {
class RenderForwardClustered : public RendererSceneRenderRD {
friend SceneShaderForwardClustered;
enum {
SCENE_UNIFORM_SET = 0,
RENDER_PASS_UNIFORM_SET = 1,
TRANSFORMS_UNIFORM_SET = 2,
MATERIAL_UNIFORM_SET = 3,
};
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,
SPEC_CONSTANT_USE_DEPTH_FOG = 12,
};
enum {
SDFGI_MAX_CASCADES = 8,
MAX_VOXEL_GI_INSTANCESS = 8,
MAX_LIGHTMAPS = 8,
MAX_VOXEL_GI_INSTANCESS_PER_INSTANCE = 2,
INSTANCE_DATA_BUFFER_MIN_SIZE = 4096
};
enum RenderListType {
RENDER_LIST_OPAQUE, //used for opaque objects
RENDER_LIST_MOTION, //used for opaque objects with motion
RENDER_LIST_ALPHA, //used for transparent objects
RENDER_LIST_SECONDARY, //used for shadows and other objects
RENDER_LIST_MAX
};
/* Scene Shader */
SceneShaderForwardClustered scene_shader;
/* Framebuffer */
class RenderBufferDataForwardClustered : public RenderBufferCustomDataRD {
GDCLASS(RenderBufferDataForwardClustered, RenderBufferCustomDataRD)
private:
RenderSceneBuffersRD *render_buffers = nullptr;
RendererRD::FSR2Context *fsr2_context = nullptr;
public:
ClusterBuilderRD *cluster_builder = nullptr;
struct SSEffectsData {
Projection last_frame_projections[RendererSceneRender::MAX_RENDER_VIEWS];
Transform3D last_frame_transform;
RendererRD::SSEffects::SSILRenderBuffers ssil;
RendererRD::SSEffects::SSAORenderBuffers ssao;
RendererRD::SSEffects::SSRRenderBuffers ssr;
} ss_effects_data;
enum DepthFrameBufferType {
DEPTH_FB,
DEPTH_FB_ROUGHNESS,
DEPTH_FB_ROUGHNESS_VOXELGI
};
RID render_sdfgi_uniform_set;
void ensure_specular();
bool has_specular() const { return render_buffers->has_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR); }
RID get_specular() const { return render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR); }
RID get_specular(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR, p_layer, 0); }
RID get_specular_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR_MSAA, p_layer, 0); }
void ensure_normal_roughness_texture();
bool has_normal_roughness() const { return render_buffers->has_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_NORMAL_ROUGHNESS); }
RID get_normal_roughness() const { return render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_NORMAL_ROUGHNESS); }
RID get_normal_roughness(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_NORMAL_ROUGHNESS, p_layer, 0); }
RID get_normal_roughness_msaa() const { return render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_NORMAL_ROUGHNESS_MSAA); }
RID get_normal_roughness_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_NORMAL_ROUGHNESS_MSAA, p_layer, 0); }
void ensure_voxelgi();
bool has_voxelgi() const { return render_buffers->has_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI); }
RID get_voxelgi() const { return render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI); }
RID get_voxelgi(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI, p_layer, 0); }
RID get_voxelgi_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI_MSAA, p_layer, 0); }
void ensure_fsr2(RendererRD::FSR2Effect *p_effect);
RendererRD::FSR2Context *get_fsr2_context() const { return fsr2_context; }
RID get_color_only_fb();
RID get_color_pass_fb(uint32_t p_color_pass_flags);
RID get_depth_fb(DepthFrameBufferType p_type = DEPTH_FB);
RID get_specular_only_fb();
RID get_velocity_only_fb();
virtual void configure(RenderSceneBuffersRD *p_render_buffers) override;
virtual void free_data() override;
};
virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) override;
RID render_base_uniform_set;
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
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, const RendererRD::MaterialStorage::Samplers &p_samplers);
RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, const RendererRD::MaterialStorage::Samplers &p_samplers, bool p_use_directional_shadow_atlas = false, int p_index = 0);
struct BestFitNormal {
BestFitNormalShaderRD shader;
RID shader_version;
RID pipeline;
RID texture;
} best_fit_normal;
enum PassMode {
PASS_MODE_COLOR,
PASS_MODE_SHADOW,
PASS_MODE_SHADOW_DP,
PASS_MODE_DEPTH,
PASS_MODE_DEPTH_NORMAL_ROUGHNESS,
PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI,
PASS_MODE_DEPTH_MATERIAL,
PASS_MODE_SDF,
};
enum ColorPassFlags {
COLOR_PASS_FLAG_TRANSPARENT = 1 << 0,
COLOR_PASS_FLAG_SEPARATE_SPECULAR = 1 << 1,
COLOR_PASS_FLAG_MULTIVIEW = 1 << 2,
COLOR_PASS_FLAG_MOTION_VECTORS = 1 << 3,
};
struct GeometryInstanceSurfaceDataCache;
struct RenderElementInfo;
struct RenderListParameters {
GeometryInstanceSurfaceDataCache **elements = nullptr;
RenderElementInfo *element_info = nullptr;
int element_count = 0;
bool reverse_cull = false;
PassMode pass_mode = PASS_MODE_COLOR;
uint32_t color_pass_flags = 0;
bool no_gi = false;
uint32_t view_count = 1;
RID render_pass_uniform_set;
bool force_wireframe = false;
Vector2 uv_offset;
float lod_distance_multiplier = 0.0;
float screen_mesh_lod_threshold = 0.0;
RD::FramebufferFormatID framebuffer_format = 0;
uint32_t element_offset = 0;
bool use_directional_soft_shadow = false;
uint32_t spec_constant_base_flags = 0;
RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, uint32_t p_color_pass_flags, 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(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_spec_constant_base_flags = 0) {
elements = p_elements;
element_info = p_element_info;
element_count = p_element_count;
reverse_cull = p_reverse_cull;
pass_mode = p_pass_mode;
color_pass_flags = p_color_pass_flags;
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;
lod_distance_multiplier = p_lod_distance_multiplier;
screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
element_offset = p_element_offset;
use_directional_soft_shadow = p_use_directional_soft_shadows;
spec_constant_base_flags = p_spec_constant_base_flags;
}
};
struct LightmapData {
float normal_xform[12];
float pad[3];
float exposure_normalization;
};
struct LightmapCaptureData {
float sh[9 * 4];
};
// When changing any of these enums, remember to change the corresponding enums in the shader files as well.
enum {
INSTANCE_DATA_FLAGS_DYNAMIC = 1 << 3,
INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,
INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 6,
INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 7,
INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 8,
INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 9,
INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 10,
INSTANCE_DATA_FLAG_PARTICLES = 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_FADE_SHIFT = 24,
INSTANCE_DATA_FLAGS_FADE_MASK = 0xFFUL << INSTANCE_DATA_FLAGS_FADE_SHIFT
};
struct SceneState {
// This struct is loaded into Set 1 - Binding 1, populated at start of rendering a frame, must match with shader code
struct UBO {
uint32_t cluster_shift;
uint32_t cluster_width;
uint32_t cluster_type_size;
uint32_t max_cluster_element_count_div_32;
uint32_t ss_effects_flags;
float ssao_light_affect;
float ssao_ao_affect;
uint32_t pad1;
float sdf_to_bounds[16];
int32_t sdf_offset[3];
uint32_t pad2;
int32_t sdf_size[3];
uint32_t gi_upscale_for_msaa;
uint32_t volumetric_fog_enabled;
float volumetric_fog_inv_length;
float volumetric_fog_detail_spread;
uint32_t volumetric_fog_pad;
};
struct PushConstant {
uint32_t base_index; //
uint32_t uv_offset; //packed
uint32_t multimesh_motion_vectors_current_offset;
uint32_t multimesh_motion_vectors_previous_offset;
};
struct InstanceData {
float transform[16];
float prev_transform[16];
uint32_t flags;
uint32_t instance_uniforms_ofs; //base offset in global buffer for instance variables
uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index)
uint32_t layer_mask;
float lightmap_uv_scale[4];
float compressed_aabb_position[4];
float compressed_aabb_size[4];
float uv_scale[4];
};
UBO ubo;
LocalVector<RID> uniform_buffers;
LocalVector<RID> implementation_uniform_buffers;
LightmapData lightmaps[MAX_LIGHTMAPS];
RID lightmap_ids[MAX_LIGHTMAPS];
bool lightmap_has_sh[MAX_LIGHTMAPS];
uint32_t lightmaps_used = 0;
uint32_t max_lightmaps;
RID lightmap_buffer;
RID instance_buffer[RENDER_LIST_MAX];
uint32_t instance_buffer_size[RENDER_LIST_MAX] = { 0, 0, 0 };
LocalVector<InstanceData> instance_data[RENDER_LIST_MAX];
LightmapCaptureData *lightmap_captures = nullptr;
uint32_t max_lightmap_captures;
RID lightmap_capture_buffer;
RID voxelgi_ids[MAX_VOXEL_GI_INSTANCESS];
uint32_t voxelgis_used = 0;
bool used_screen_texture = false;
bool used_normal_texture = false;
bool used_depth_texture = false;
bool used_sss = false;
bool used_lightmap = false;
struct ShadowPass {
uint32_t element_from;
uint32_t element_count;
bool flip_cull;
PassMode pass_mode;
RID rp_uniform_set;
float lod_distance_multiplier;
float screen_mesh_lod_threshold;
RID framebuffer;
RD::InitialAction initial_depth_action;
Rect2i rect;
};
LocalVector<ShadowPass> shadow_passes;
} scene_state;
static RenderForwardClustered *singleton;
void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_apply_alpha_multiplier = false, bool p_pancake_shadows = false, int p_index = 0);
void _setup_voxelgis(const PagedArray<RID> &p_voxelgis);
void _setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
struct RenderElementInfo {
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;
};
template <PassMode p_pass_mode, uint32_t p_color_pass_flags = 0>
_FORCE_INLINE_ void _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);
void _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);
void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 0.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
void _update_instance_data_buffer(RenderListType p_render_list);
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_using_motion_pass = false, bool p_append = false);
HashMap<Size2i, RID> sdfgi_framebuffer_size_cache;
struct GeometryInstanceData;
class GeometryInstanceForwardClustered;
struct GeometryInstanceLightmapSH {
Color sh[9];
};
// Cached data for drawing surfaces
struct GeometryInstanceSurfaceDataCache {
enum {
FLAG_PASS_DEPTH = 1,
FLAG_PASS_OPAQUE = 2,
FLAG_PASS_ALPHA = 4,
FLAG_PASS_SHADOW = 8,
FLAG_USES_SHARED_SHADOW_MATERIAL = 128,
FLAG_USES_SUBSURFACE_SCATTERING = 2048,
FLAG_USES_SCREEN_TEXTURE = 4096,
FLAG_USES_DEPTH_TEXTURE = 8192,
FLAG_USES_NORMAL_TEXTURE = 16384,
FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768,
FLAG_USES_PARTICLE_TRAILS = 65536,
FLAG_USES_MOTION_VECTOR = 131072,
};
union {
struct {
uint64_t lod_index : 8;
uint64_t surface_index : 8;
uint64_t geometry_id : 32;
uint64_t material_id_low : 16;
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;
uint64_t priority : 8;
};
struct {
uint64_t sort_key1;
uint64_t sort_key2;
};
} sort;
RS::PrimitiveType primitive = RS::PRIMITIVE_MAX;
uint32_t flags = 0;
uint32_t surface_index = 0;
uint32_t color_pass_inclusion_mask = 0;
void *surface = nullptr;
RID material_uniform_set;
SceneShaderForwardClustered::ShaderData *shader = nullptr;
SceneShaderForwardClustered::MaterialData *material = nullptr;
void *surface_shadow = nullptr;
RID material_uniform_set_shadow;
SceneShaderForwardClustered::ShaderData *shader_shadow = nullptr;
GeometryInstanceSurfaceDataCache *next = nullptr;
GeometryInstanceForwardClustered *owner = nullptr;
};
class GeometryInstanceForwardClustered : public RenderGeometryInstanceBase {
public:
// lightmap
RID lightmap_instance;
Rect2 lightmap_uv_scale;
uint32_t lightmap_slice_index;
GeometryInstanceLightmapSH *lightmap_sh = nullptr;
//used during rendering
uint32_t gi_offset_cache = 0;
bool store_transform_cache = true;
RID transforms_uniform_set;
uint32_t instance_count = 0;
uint32_t trail_steps = 1;
bool can_sdfgi = false;
bool using_projectors = false;
bool using_softshadows = false;
//used during setup
uint64_t prev_transform_change_frame = 0xFFFFFFFF;
bool prev_transform_dirty = true;
Transform3D prev_transform;
RID voxel_gi_instances[MAX_VOXEL_GI_INSTANCESS_PER_INSTANCE];
GeometryInstanceSurfaceDataCache *surface_caches = nullptr;
SelfList<GeometryInstanceForwardClustered> dirty_list_element;
GeometryInstanceForwardClustered() :
dirty_list_element(this) {}
virtual void _mark_dirty() override;
virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override;
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override;
virtual void set_lightmap_capture(const Color *p_sh9) override;
virtual void pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) override {}
virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {}
virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {}
virtual void pair_voxel_gi_instances(const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override;
virtual void set_softshadow_projector_pairing(bool p_softshadow, bool p_projector) override;
};
static void _geometry_instance_dependency_changed(Dependency::DependencyChangedNotification p_notification, DependencyTracker *p_tracker);
static void _geometry_instance_dependency_deleted(const RID &p_dependency, DependencyTracker *p_tracker);
SelfList<GeometryInstanceForwardClustered>::List geometry_instance_dirty_list;
PagedAllocator<GeometryInstanceForwardClustered> geometry_instance_alloc;
PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc;
PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh;
void _geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh);
void _geometry_instance_add_surface_with_material_chain(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, RID p_mat_src, RID p_mesh);
void _geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh);
void _geometry_instance_update(RenderGeometryInstance *p_geometry_instance);
void _update_dirty_geometry_instances();
/* Render List */
struct RenderList {
LocalVector<GeometryInstanceSurfaceDataCache *> elements;
LocalVector<RenderElementInfo> element_info;
void clear() {
elements.clear();
element_info.clear();
}
//should eventually be replaced by radix
struct SortByKey {
_FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const {
return (A->sort.sort_key2 == B->sort.sort_key2) ? (A->sort.sort_key1 < B->sort.sort_key1) : (A->sort.sort_key2 < B->sort.sort_key2);
}
};
void sort_by_key() {
SortArray<GeometryInstanceSurfaceDataCache *, SortByKey> sorter;
sorter.sort(elements.ptr(), elements.size());
}
void sort_by_key_range(uint32_t p_from, uint32_t p_size) {
SortArray<GeometryInstanceSurfaceDataCache *, SortByKey> sorter;
sorter.sort(elements.ptr() + p_from, p_size);
}
struct SortByDepth {
_FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const {
return (A->owner->depth < B->owner->depth);
}
};
void sort_by_depth() { //used for shadows
SortArray<GeometryInstanceSurfaceDataCache *, SortByDepth> sorter;
sorter.sort(elements.ptr(), elements.size());
}
struct SortByReverseDepthAndPriority {
_FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const {
return (A->sort.priority == B->sort.priority) ? (A->owner->depth > B->owner->depth) : (A->sort.priority < B->sort.priority);
}
};
void sort_by_reverse_depth_and_priority() { //used for alpha
SortArray<GeometryInstanceSurfaceDataCache *, SortByReverseDepthAndPriority> sorter;
sorter.sort(elements.ptr(), elements.size());
}
_FORCE_INLINE_ void add_element(GeometryInstanceSurfaceDataCache *p_element) {
elements.push_back(p_element);
}
};
RenderList render_list[RENDER_LIST_MAX];
virtual void _update_shader_quality_settings() override;
/* Effects */
RendererRD::Resolve *resolve_effects = nullptr;
RendererRD::TAA *taa = nullptr;
RendererRD::FSR2Effect *fsr2_effect = nullptr;
RendererRD::SSEffects *ss_effects = nullptr;
/* Cluster builder */
ClusterBuilderSharedDataRD cluster_builder_shared;
ClusterBuilderRD *current_cluster_builder = nullptr;
/* SDFGI */
void _update_sdfgi(RenderDataRD *p_render_data);
/* Volumetric fog */
RID shadow_sampler;
void _update_volumetric_fog(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_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);
/* Render shadows */
void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1), const Transform3D &p_main_cam_transform = Transform3D());
void _render_shadow_begin();
void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_reverse_cull_face, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, float p_lod_distance_multiplier = 0.0, float p_screen_mesh_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, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1), const Transform3D &p_main_cam_transform = Transform3D());
void _render_shadow_process();
void _render_shadow_end();
/* Render Scene */
void _process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const RID *p_normal_buffers, const Projection *p_projections);
void _process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const RID *p_normal_buffers, const Projection *p_projections, const Transform3D &p_transform);
void _copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers);
void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer);
void _process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_buffer_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive);
void _process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera);
/* Debug */
void _debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers);
protected:
/* setup */
virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) 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;
virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override;
virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override;
virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override;
virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override;
/* Rendering */
virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
virtual void _render_buffers_debug_draw(const RenderDataRD *p_render_data) override;
virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) override;
virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
virtual void _render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) override;
virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) override;
public:
static RenderForwardClustered *get_singleton() { return singleton; }
ClusterBuilderSharedDataRD *get_cluster_builder_shared() { return &cluster_builder_shared; }
RendererRD::SSEffects *get_ss_effects() { return ss_effects; }
/* callback from updating our lighting UBOs, used to populate cluster builder */
virtual void setup_added_reflection_probe(const Transform3D &p_transform, const Vector3 &p_half_size) override;
virtual void setup_added_light(const RS::LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture) override;
virtual void setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_size) override;
virtual void base_uniforms_changed() override;
/* SDFGI UPDATE */
virtual void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override;
virtual int sdfgi_get_pending_region_count(const Ref<RenderSceneBuffers> &p_render_buffers) const override;
virtual AABB sdfgi_get_pending_region_bounds(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override;
virtual uint32_t sdfgi_get_pending_region_cascade(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override;
RID sdfgi_get_ubo() const { return gi.sdfgi_ubo; }
/* GEOMETRY INSTANCE */
virtual RenderGeometryInstance *geometry_instance_create(RID p_base) override;
virtual void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) override;
virtual uint32_t geometry_instance_get_pair_mask() override;
virtual bool free(RID p_rid) override;
RenderForwardClustered();
~RenderForwardClustered();
};
} // namespace RendererSceneRenderImplementation
#endif // RENDER_FORWARD_CLUSTERED_H

View file

@ -0,0 +1,871 @@
/**************************************************************************/
/* scene_shader_forward_clustered.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "scene_shader_forward_clustered.h"
#include "core/config/project_settings.h"
#include "core/math/math_defs.h"
#include "render_forward_clustered.h"
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
using namespace RendererSceneRenderImplementation;
void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
//compile
code = p_code;
valid = false;
ubo_size = 0;
uniforms.clear();
if (code.is_empty()) {
return; //just invalid, but no error
}
ShaderCompiler::GeneratedCode gen_code;
int blend_mode = BLEND_MODE_MIX;
int depth_testi = DEPTH_TEST_ENABLED;
int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
int cull_modei = CULL_BACK;
uses_point_size = false;
uses_alpha = false;
uses_alpha_clip = false;
uses_alpha_antialiasing = false;
uses_blend_alpha = false;
uses_depth_prepass_alpha = false;
uses_discard = false;
uses_roughness = false;
uses_normal = false;
uses_tangent = false;
bool uses_normal_map = false;
bool wireframe = false;
unshaded = false;
uses_vertex = false;
uses_position = false;
uses_sss = false;
uses_transmittance = false;
uses_time = false;
writes_modelview_or_projection = false;
uses_world_coordinates = false;
uses_particle_trails = false;
int depth_drawi = DEPTH_DRAW_OPAQUE;
ShaderCompiler::IdentifierActions actions;
actions.entry_point_stages["vertex"] = ShaderCompiler::STAGE_VERTEX;
actions.entry_point_stages["fragment"] = ShaderCompiler::STAGE_FRAGMENT;
actions.entry_point_stages["light"] = ShaderCompiler::STAGE_FRAGMENT;
actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD);
actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PREMULT_ALPHA);
actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE);
actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED);
actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_modei, CULL_DISABLED);
actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_modei, CULL_FRONT);
actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull_modei, CULL_BACK);
actions.render_mode_flags["unshaded"] = &unshaded;
actions.render_mode_flags["wireframe"] = &wireframe;
actions.render_mode_flags["particle_trails"] = &uses_particle_trails;
actions.render_mode_flags["world_vertex_coords"] = &uses_world_coordinates;
actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
actions.usage_flag_pointers["ALPHA_SCISSOR_THRESHOLD"] = &uses_alpha_clip;
actions.usage_flag_pointers["ALPHA_HASH_SCALE"] = &uses_alpha_clip;
actions.usage_flag_pointers["ALPHA_ANTIALIASING_EDGE"] = &uses_alpha_antialiasing;
actions.usage_flag_pointers["ALPHA_TEXTURE_COORDINATE"] = &uses_alpha_antialiasing;
actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_prepass_alpha;
actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance;
actions.usage_flag_pointers["DISCARD"] = &uses_discard;
actions.usage_flag_pointers["TIME"] = &uses_time;
actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness;
actions.usage_flag_pointers["NORMAL"] = &uses_normal;
actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal_map;
actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size;
actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size;
actions.usage_flag_pointers["TANGENT"] = &uses_tangent;
actions.usage_flag_pointers["BINORMAL"] = &uses_tangent;
actions.usage_flag_pointers["ANISOTROPY"] = &uses_tangent;
actions.usage_flag_pointers["ANISOTROPY_FLOW"] = &uses_tangent;
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_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = shader_singleton->shader.version_create();
}
depth_draw = DepthDraw(depth_drawi);
depth_test = DepthTest(depth_testi);
cull_mode = Cull(cull_modei);
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
uses_screen_texture = gen_code.uses_screen_texture;
uses_depth_texture = gen_code.uses_depth_texture;
uses_normal_texture = gen_code.uses_normal_roughness_texture;
uses_vertex_time = gen_code.uses_vertex_time;
uses_fragment_time = gen_code.uses_fragment_time;
uses_normal |= uses_normal_map;
uses_tangent |= uses_normal_map;
#if 0
print_line("**compiling shader:");
print_line("**defines:\n");
for (int i = 0; i < gen_code.defines.size(); i++) {
print_line(gen_code.defines[i]);
}
HashMap<String, String>::Iterator el = gen_code.code.begin();
while (el) {
print_line("\n**code " + el->key + ":\n" + el->value);
++el;
}
print_line("\n**uniforms:\n" + gen_code.uniforms);
print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]);
print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
#endif
shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines);
ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version));
ubo_size = gen_code.uniform_total_size;
ubo_offsets = gen_code.uniform_offsets;
texture_uniforms = gen_code.texture_uniforms;
//blend modes
// if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage
if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) {
blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE;
}
RD::PipelineColorBlendState::Attachment blend_attachment;
switch (blend_mode) {
case BLEND_MODE_MIX: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
} break;
case BLEND_MODE_ADD: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
uses_blend_alpha = true; //force alpha used because of blend
} break;
case BLEND_MODE_SUB: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_REVERSE_SUBTRACT;
blend_attachment.color_blend_op = RD::BLEND_OP_REVERSE_SUBTRACT;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
uses_blend_alpha = true; //force alpha used because of blend
} break;
case BLEND_MODE_MUL: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
uses_blend_alpha = true; //force alpha used because of blend
} break;
case BLEND_MODE_ALPHA_TO_COVERAGE: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
} break;
case BLEND_MODE_PREMULT_ALPHA: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
uses_blend_alpha = true; // Force alpha used because of blend.
} break;
}
// Color pass -> attachment 0: Color/Diffuse, attachment 1: Separate Specular, attachment 2: Motion Vectors
RD::PipelineColorBlendState blend_state_color_blend;
blend_state_color_blend.attachments = { blend_attachment, RD::PipelineColorBlendState::Attachment(), RD::PipelineColorBlendState::Attachment() };
RD::PipelineColorBlendState blend_state_color_opaque = RD::PipelineColorBlendState::create_disabled(3);
RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1);
RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2);
//update pipelines
RD::PipelineDepthStencilState depth_stencil_state;
if (depth_test != DEPTH_TEST_DISABLED) {
depth_stencil_state.enable_depth_test = true;
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
}
bool depth_pre_pass_enabled = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable"));
for (int i = 0; i < CULL_VARIANT_MAX; i++) {
RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = {
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK },
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT },
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED }
};
RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull_mode];
for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
RD::RENDER_PRIMITIVE_POINTS,
RD::RENDER_PRIMITIVE_LINES,
RD::RENDER_PRIMITIVE_LINESTRIPS,
RD::RENDER_PRIMITIVE_TRIANGLES,
RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
};
RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j];
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_DEPTH_PASS_MULTIVIEW,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW,
SHADER_VERSION_COLOR_PASS,
};
shader_version = shader_version_table[k];
if (!static_cast<SceneShaderForwardClustered *>(singleton)->shader.is_variant_enabled(shader_version)) {
continue;
}
RD::PipelineRasterizationState raster_state;
raster_state.cull_mode = cull_mode_rd;
raster_state.wireframe = wireframe;
if (k == PIPELINE_VERSION_COLOR_PASS) {
for (int l = 0; l < PIPELINE_COLOR_PASS_FLAG_COUNT; l++) {
if (!shader_singleton->valid_color_pass_pipelines[l]) {
continue;
}
RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
RD::PipelineColorBlendState blend_state;
RD::PipelineMultisampleState multisample_state;
int shader_flags = 0;
if (l & PIPELINE_COLOR_PASS_FLAG_TRANSPARENT) {
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) {
multisample_state.enable_alpha_to_coverage = true;
multisample_state.enable_alpha_to_one = true;
}
blend_state = blend_state_color_blend;
if (depth_draw == DEPTH_DRAW_OPAQUE) {
depth_stencil.enable_depth_write = false; //alpha does not draw depth
}
} else {
blend_state = blend_state_color_opaque;
if (depth_pre_pass_enabled) {
// We already have a depth from the depth pre-pass, there is no need to write it again.
// In addition we can use COMPARE_OP_EQUAL instead of COMPARE_OP_LESS_OR_EQUAL.
// This way we can use the early depth test to discard transparent fragments before the fragment shader even starts.
depth_stencil.depth_compare_operator = RD::COMPARE_OP_EQUAL;
depth_stencil.enable_depth_write = false;
}
if (l & PIPELINE_COLOR_PASS_FLAG_SEPARATE_SPECULAR) {
shader_flags |= SHADER_COLOR_PASS_FLAG_SEPARATE_SPECULAR;
}
}
if (l & PIPELINE_COLOR_PASS_FLAG_MOTION_VECTORS) {
shader_flags |= SHADER_COLOR_PASS_FLAG_MOTION_VECTORS;
}
if (l & PIPELINE_COLOR_PASS_FLAG_LIGHTMAP) {
shader_flags |= SHADER_COLOR_PASS_FLAG_LIGHTMAP;
}
if (l & PIPELINE_COLOR_PASS_FLAG_MULTIVIEW) {
shader_flags |= SHADER_COLOR_PASS_FLAG_MULTIVIEW;
}
int variant = shader_version + shader_flags;
if (!static_cast<SceneShaderForwardClustered *>(singleton)->shader.is_variant_enabled(variant)) {
continue;
}
RID shader_variant = shader_singleton->shader.version_get_shader(version, variant);
color_pipelines[i][j][l].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0, singleton->default_specialization_constants);
}
} else {
RD::PipelineColorBlendState blend_state;
RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
RD::PipelineMultisampleState multisample_state;
if (k == PIPELINE_VERSION_DEPTH_PASS || k == PIPELINE_VERSION_DEPTH_PASS_DP || k == PIPELINE_VERSION_DEPTH_PASS_MULTIVIEW) {
//none, leave empty
} else if (k == PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW) {
blend_state = blend_state_depth_normal_roughness;
} else if (k == PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI || k == PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW) {
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
}
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);
}
}
}
}
valid = true;
}
bool SceneShaderForwardClustered::ShaderData::is_animated() const {
return (uses_fragment_time && uses_discard) || (uses_vertex_time && uses_vertex);
}
bool SceneShaderForwardClustered::ShaderData::casts_shadows() const {
bool has_read_screen_alpha = uses_screen_texture || uses_depth_texture || uses_normal_texture;
bool has_base_alpha = (uses_alpha && (!uses_alpha_clip || uses_alpha_antialiasing)) || has_read_screen_alpha;
bool has_alpha = has_base_alpha || uses_blend_alpha;
return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED));
}
RS::ShaderNativeSourceCode SceneShaderForwardClustered::ShaderData::get_native_source_code() const {
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
return shader_singleton->shader.version_get_native_source_code(version);
}
SceneShaderForwardClustered::ShaderData::ShaderData() :
shader_list_element(this) {
}
SceneShaderForwardClustered::ShaderData::~ShaderData() {
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
ERR_FAIL_NULL(shader_singleton);
//pipeline variants will clear themselves if shader is gone
if (version.is_valid()) {
shader_singleton->shader.version_free(version);
}
}
RendererRD::MaterialStorage::ShaderData *SceneShaderForwardClustered::_create_shader_func() {
ShaderData *shader_data = memnew(ShaderData);
singleton->shader_list.add(&shader_data->shader_list_element);
return shader_data;
}
void SceneShaderForwardClustered::MaterialData::set_render_priority(int p_priority) {
priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits
}
void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) {
next_pass = p_pass;
}
bool SceneShaderForwardClustered::MaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
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, true, true);
}
SceneShaderForwardClustered::MaterialData::~MaterialData() {
free_parameters_uniform_set(uniform_set);
}
RendererRD::MaterialStorage::MaterialData *SceneShaderForwardClustered::_create_material_func(ShaderData *p_shader) {
MaterialData *material_data = memnew(MaterialData);
material_data->shader_data = p_shader;
//update will happen later anyway so do nothing.
return material_data;
}
SceneShaderForwardClustered *SceneShaderForwardClustered::singleton = nullptr;
SceneShaderForwardClustered::SceneShaderForwardClustered() {
// there should be only one of these, contained within our RenderFM singleton.
singleton = this;
}
SceneShaderForwardClustered::~SceneShaderForwardClustered() {
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
RD::get_singleton()->free(default_vec4_xform_buffer);
RD::get_singleton()->free(shadow_sampler);
material_storage->shader_free(overdraw_material_shader);
material_storage->shader_free(default_shader);
material_storage->shader_free(debug_shadow_splits_material_shader);
material_storage->material_free(overdraw_material);
material_storage->material_free(default_material);
material_storage->material_free(debug_shadow_splits_material);
}
void SceneShaderForwardClustered::init(const String p_defines) {
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
{
Vector<ShaderRD::VariantDefine> shader_versions;
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, "\n#define MODE_RENDER_DEPTH\n", true)); // SHADER_VERSION_DEPTH_PASS
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, "\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n", true)); // SHADER_VERSION_DEPTH_PASS_DP
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n", true)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_ADVANCED, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_VOXEL_GI\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_ADVANCED, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_ADVANCED, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_SDF
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n", false)); // SHADER_VERSION_DEPTH_PASS_MULTIVIEW
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_VOXEL_GI\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW
Vector<String> color_pass_flags = {
"\n#define MODE_SEPARATE_SPECULAR\n", // SHADER_COLOR_PASS_FLAG_SEPARATE_SPECULAR
"\n#define USE_LIGHTMAP\n", // SHADER_COLOR_PASS_FLAG_LIGHTMAP
"\n#define USE_MULTIVIEW\n", // SHADER_COLOR_PASS_FLAG_MULTIVIEW
"\n#define MOTION_VECTORS\n", // SHADER_COLOR_PASS_FLAG_MOTION_VECTORS
};
for (int i = 0; i < SHADER_COLOR_PASS_FLAG_COUNT; i++) {
String version = "";
for (int j = 0; (1 << j) < SHADER_COLOR_PASS_FLAG_COUNT; j += 1) {
if ((1 << j) & i) {
version += color_pass_flags[j];
}
}
// Assign a group based on what features this pass contains.
ShaderGroup group = SHADER_GROUP_BASE;
bool advanced_group = (i & SHADER_COLOR_PASS_FLAG_SEPARATE_SPECULAR) || (i & SHADER_COLOR_PASS_FLAG_LIGHTMAP) || (i & SHADER_COLOR_PASS_FLAG_MOTION_VECTORS);
bool multiview_group = i & SHADER_COLOR_PASS_FLAG_MULTIVIEW;
if (advanced_group && multiview_group) {
group = SHADER_GROUP_ADVANCED_MULTIVIEW;
} else if (advanced_group) {
group = SHADER_GROUP_ADVANCED;
} else if (multiview_group) {
group = SHADER_GROUP_MULTIVIEW;
}
shader_versions.push_back(ShaderRD::VariantDefine(group, version, false));
}
shader.initialize(shader_versions, p_defines);
if (RendererCompositorRD::get_singleton()->is_xr_enabled()) {
shader.enable_group(SHADER_GROUP_MULTIVIEW);
}
}
// Set flag to true if a combination is valid.
// The only invalid combinations are those that include both TRANSPARENT and SEPARATE_SPECULAR.
for (int i = 0; i < PIPELINE_COLOR_PASS_FLAG_COUNT; i++) {
if ((i & PIPELINE_COLOR_PASS_FLAG_TRANSPARENT) && (i & PIPELINE_COLOR_PASS_FLAG_SEPARATE_SPECULAR)) {
valid_color_pass_pipelines[i] = false;
} else {
valid_color_pass_pipelines[i] = true;
}
}
material_storage->shader_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_3D, _create_shader_funcs);
material_storage->material_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_3D, _create_material_funcs);
{
//shader compiler
ShaderCompiler::DefaultIdentifierActions actions;
actions.renames["MODEL_MATRIX"] = "read_model_matrix";
actions.renames["MODEL_NORMAL_MATRIX"] = "model_normal_matrix";
actions.renames["VIEW_MATRIX"] = "read_view_matrix";
actions.renames["INV_VIEW_MATRIX"] = "inv_view_matrix";
actions.renames["PROJECTION_MATRIX"] = "projection_matrix";
actions.renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix";
actions.renames["MODELVIEW_MATRIX"] = "modelview";
actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal";
actions.renames["MAIN_CAM_INV_VIEW_MATRIX"] = "scene_data.main_cam_inv_view_matrix";
actions.renames["VERTEX"] = "vertex";
actions.renames["NORMAL"] = "normal";
actions.renames["TANGENT"] = "tangent";
actions.renames["BINORMAL"] = "binormal";
actions.renames["POSITION"] = "position";
actions.renames["UV"] = "uv_interp";
actions.renames["UV2"] = "uv2_interp";
actions.renames["COLOR"] = "color_interp";
actions.renames["POINT_SIZE"] = "gl_PointSize";
actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
actions.renames["VERTEX_ID"] = "gl_VertexIndex";
actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold";
actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale";
actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge";
actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate";
//builtins
actions.renames["TIME"] = "global_time";
actions.renames["EXPOSURE"] = "(1.0 / scene_data_block.data.emissive_exposure_normalization)";
actions.renames["PI"] = _MKSTR(Math_PI);
actions.renames["TAU"] = _MKSTR(Math_TAU);
actions.renames["E"] = _MKSTR(Math_E);
actions.renames["VIEWPORT_SIZE"] = "read_viewport_size";
actions.renames["FRAGCOORD"] = "gl_FragCoord";
actions.renames["FRONT_FACING"] = "gl_FrontFacing";
actions.renames["NORMAL_MAP"] = "normal_map";
actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth";
actions.renames["ALBEDO"] = "albedo";
actions.renames["ALPHA"] = "alpha";
actions.renames["PREMUL_ALPHA_FACTOR"] = "premul_alpha";
actions.renames["METALLIC"] = "metallic";
actions.renames["SPECULAR"] = "specular";
actions.renames["ROUGHNESS"] = "roughness";
actions.renames["RIM"] = "rim";
actions.renames["RIM_TINT"] = "rim_tint";
actions.renames["CLEARCOAT"] = "clearcoat";
actions.renames["CLEARCOAT_ROUGHNESS"] = "clearcoat_roughness";
actions.renames["ANISOTROPY"] = "anisotropy";
actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
actions.renames["SSS_STRENGTH"] = "sss_strength";
actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color";
actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth";
actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost";
actions.renames["BACKLIGHT"] = "backlight";
actions.renames["AO"] = "ao";
actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
actions.renames["EMISSION"] = "emission";
actions.renames["POINT_COORD"] = "gl_PointCoord";
actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
actions.renames["SCREEN_UV"] = "screen_uv";
actions.renames["DEPTH"] = "gl_FragDepth";
actions.renames["FOG"] = "fog";
actions.renames["RADIANCE"] = "custom_radiance";
actions.renames["IRRADIANCE"] = "custom_irradiance";
actions.renames["BONE_INDICES"] = "bone_attrib";
actions.renames["BONE_WEIGHTS"] = "weight_attrib";
actions.renames["CUSTOM0"] = "custom0_attrib";
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["LIGHT_VERTEX"] = "light_vertex";
actions.renames["NODE_POSITION_WORLD"] = "read_model_matrix[3].xyz";
actions.renames["CAMERA_POSITION_WORLD"] = "scene_data.inv_view_matrix[3].xyz";
actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.inv_view_matrix[2].xyz";
actions.renames["CAMERA_VISIBLE_LAYERS"] = "scene_data.camera_visible_layers";
actions.renames["NODE_POSITION_VIEW"] = "(scene_data.view_matrix * read_model_matrix)[3].xyz";
actions.renames["VIEW_INDEX"] = "ViewIndex";
actions.renames["VIEW_MONO_LEFT"] = "0";
actions.renames["VIEW_RIGHT"] = "1";
actions.renames["EYE_OFFSET"] = "eye_offset";
//for light
actions.renames["VIEW"] = "view";
actions.renames["SPECULAR_AMOUNT"] = "specular_amount";
actions.renames["LIGHT_COLOR"] = "light_color";
actions.renames["LIGHT_IS_DIRECTIONAL"] = "is_directional";
actions.renames["LIGHT"] = "light";
actions.renames["ATTENUATION"] = "attenuation";
actions.renames["DIFFUSE_LIGHT"] = "diffuse_light";
actions.renames["SPECULAR_LIGHT"] = "specular_light";
actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n";
actions.usage_defines["BINORMAL"] = "@TANGENT";
actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n";
actions.usage_defines["RIM_TINT"] = "@RIM";
actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n";
actions.usage_defines["CLEARCOAT_ROUGHNESS"] = "@CLEARCOAT";
actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n";
actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
actions.usage_defines["AO"] = "#define AO_USED\n";
actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
actions.usage_defines["UV"] = "#define UV_USED\n";
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_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";
actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
actions.usage_defines["LIGHT_VERTEX"] = "#define LIGHT_VERTEX_USED\n";
actions.usage_defines["PREMUL_ALPHA_FACTOR"] = "#define PREMUL_ALPHA_USED\n";
actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n";
actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n";
actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n";
actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE";
actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";
actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n";
actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n";
actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n";
actions.usage_defines["MODEL_MATRIX"] = "#define MODEL_MATRIX_USED\n";
actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
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_prepass_alpha"] = "#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_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n";
actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
actions.render_mode_defines["debug_shadow_splits"] = "#define DEBUG_DRAW_PSSM_SPLITS\n";
actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET;
actions.base_uniform_string = "material.";
actions.base_varying_index = 12;
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
actions.global_buffer_array_variable = "global_shader_uniforms.data";
actions.instance_uniform_index_variable = "instances.data[instance_index_interp].instance_uniforms_ofs";
actions.check_multiview_samplers = RendererCompositorRD::get_singleton()->is_xr_enabled(); // Make sure we check sampling multiview textures.
compiler.initialize(actions);
}
{
//default material and shader
default_shader = material_storage->shader_allocate();
material_storage->shader_initialize(default_shader);
material_storage->shader_set_code(default_shader, R"(
// Default 3D material shader (Forward+).
shader_type spatial;
void vertex() {
ROUGHNESS = 0.8;
}
void fragment() {
ALBEDO = vec3(0.6);
ROUGHNESS = 0.8;
METALLIC = 0.2;
}
)");
default_material = material_storage->material_allocate();
material_storage->material_initialize(default_material);
material_storage->material_set_shader(default_material, default_shader);
MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(default_material, RendererRD::MaterialStorage::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 = material_storage->shader_allocate();
material_storage->shader_initialize(overdraw_material_shader);
// Use relatively low opacity so that more "layers" of overlapping objects can be distinguished.
material_storage->shader_set_code(overdraw_material_shader, R"(
// 3D editor Overdraw debug draw mode shader (Forward+).
shader_type spatial;
render_mode blend_add, unshaded, fog_disabled;
void fragment() {
ALBEDO = vec3(0.4, 0.8, 0.8);
ALPHA = 0.1;
}
)");
overdraw_material = material_storage->material_allocate();
material_storage->material_initialize(overdraw_material);
material_storage->material_set_shader(overdraw_material, overdraw_material_shader);
MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(overdraw_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
overdraw_material_shader_ptr = md->shader_data;
overdraw_material_uniform_set = md->uniform_set;
}
{
debug_shadow_splits_material_shader = material_storage->shader_allocate();
material_storage->shader_initialize(debug_shadow_splits_material_shader);
material_storage->shader_set_code(debug_shadow_splits_material_shader, R"(
// 3D debug shadow splits mode shader (Forward+).
shader_type spatial;
render_mode debug_shadow_splits, fog_disabled;
void fragment() {
ALBEDO = vec3(1.0, 1.0, 1.0);
}
)");
debug_shadow_splits_material = material_storage->material_allocate();
material_storage->material_initialize(debug_shadow_splits_material);
material_storage->material_set_shader(debug_shadow_splits_material, debug_shadow_splits_material_shader);
MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(debug_shadow_splits_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
debug_shadow_splits_material_shader_ptr = md->shader_data;
debug_shadow_splits_material_uniform_set = md->uniform_set;
}
{
default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256);
Vector<RD::Uniform> uniforms;
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(default_vec4_xform_buffer);
u.binding = 0;
uniforms.push_back(u);
default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RenderForwardClustered::TRANSFORMS_UNIFORM_SET);
}
{
RD::SamplerState sampler;
sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
sampler.enable_compare = true;
sampler.compare_op = RD::COMPARE_OP_GREATER;
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);
}
for (int k = 0; k < PIPELINE_COLOR_PASS_FLAG_COUNT; k++) {
E->self()->color_pipelines[i][j][k].update_specialization_constants(default_specialization_constants);
}
}
}
}
}
void SceneShaderForwardClustered::enable_advanced_shader_group(bool p_needs_multiview) {
if (p_needs_multiview || RendererCompositorRD::get_singleton()->is_xr_enabled()) {
shader.enable_group(SHADER_GROUP_ADVANCED_MULTIVIEW);
}
shader.enable_group(SHADER_GROUP_ADVANCED);
}

View file

@ -0,0 +1,265 @@
/**************************************************************************/
/* scene_shader_forward_clustered.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 SCENE_SHADER_FORWARD_CLUSTERED_H
#define SCENE_SHADER_FORWARD_CLUSTERED_H
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
#include "servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl.gen.h"
namespace RendererSceneRenderImplementation {
class SceneShaderForwardClustered {
private:
static SceneShaderForwardClustered *singleton;
public:
enum ShaderGroup {
SHADER_GROUP_BASE, // Always compiled at the beginning.
SHADER_GROUP_ADVANCED,
SHADER_GROUP_MULTIVIEW,
SHADER_GROUP_ADVANCED_MULTIVIEW,
};
enum ShaderVersion {
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_DEPTH_PASS_MULTIVIEW,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW,
SHADER_VERSION_COLOR_PASS,
SHADER_VERSION_MAX
};
enum ShaderColorPassFlags {
SHADER_COLOR_PASS_FLAG_SEPARATE_SPECULAR = 1 << 0,
SHADER_COLOR_PASS_FLAG_LIGHTMAP = 1 << 1,
SHADER_COLOR_PASS_FLAG_MULTIVIEW = 1 << 2,
SHADER_COLOR_PASS_FLAG_MOTION_VECTORS = 1 << 3,
SHADER_COLOR_PASS_FLAG_COUNT = 1 << 4
};
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_DEPTH_PASS_MULTIVIEW,
PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW,
PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW,
PIPELINE_VERSION_COLOR_PASS,
PIPELINE_VERSION_MAX
};
enum PipelineColorPassFlags {
PIPELINE_COLOR_PASS_FLAG_TRANSPARENT = 1 << 0, // Can't combine with SEPARATE_SPECULAR.
PIPELINE_COLOR_PASS_FLAG_SEPARATE_SPECULAR = 1 << 1, // Can't combine with TRANSPARENT.
PIPELINE_COLOR_PASS_FLAG_LIGHTMAP = 1 << 2,
PIPELINE_COLOR_PASS_FLAG_MULTIVIEW = 1 << 3,
PIPELINE_COLOR_PASS_FLAG_MOTION_VECTORS = 1 << 4,
PIPELINE_COLOR_PASS_FLAG_COUNT = 1 << 5,
};
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 RendererRD::MaterialStorage::ShaderData {
enum BlendMode { //used internally
BLEND_MODE_MIX,
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL,
BLEND_MODE_ALPHA_TO_COVERAGE,
BLEND_MODE_PREMULT_ALPHA,
};
enum DepthDraw {
DEPTH_DRAW_DISABLED,
DEPTH_DRAW_OPAQUE,
DEPTH_DRAW_ALWAYS
};
enum DepthTest {
DEPTH_TEST_DISABLED,
DEPTH_TEST_ENABLED
};
enum Cull {
CULL_DISABLED,
CULL_FRONT,
CULL_BACK
};
enum CullVariant {
CULL_VARIANT_NORMAL,
CULL_VARIANT_REVERSED,
CULL_VARIANT_DOUBLE_SIDED,
CULL_VARIANT_MAX
};
enum AlphaAntiAliasing {
ALPHA_ANTIALIASING_OFF,
ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
};
bool valid = false;
RID version;
uint64_t vertex_input_mask = 0;
PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_VERSION_MAX];
PipelineCacheRD color_pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_COLOR_PASS_FLAG_COUNT];
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size = 0;
String code;
DepthDraw depth_draw = DEPTH_DRAW_OPAQUE;
DepthTest depth_test = DEPTH_TEST_ENABLED;
bool uses_point_size = false;
bool uses_alpha = false;
bool uses_blend_alpha = false;
bool uses_alpha_clip = false;
bool uses_alpha_antialiasing = false;
bool uses_depth_prepass_alpha = false;
bool uses_discard = false;
bool uses_roughness = false;
bool uses_normal = false;
bool uses_tangent = false;
bool uses_particle_trails = false;
bool unshaded = false;
bool uses_vertex = false;
bool uses_position = false;
bool uses_sss = false;
bool uses_transmittance = false;
bool uses_screen_texture = false;
bool uses_depth_texture = false;
bool uses_normal_texture = false;
bool uses_time = false;
bool uses_vertex_time = false;
bool uses_fragment_time = false;
bool writes_modelview_or_projection = false;
bool uses_world_coordinates = false;
bool uses_screen_texture_mipmaps = false;
Cull cull_mode = CULL_DISABLED;
uint64_t last_pass = 0;
uint32_t index = 0;
virtual void set_code(const String &p_Code);
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
SelfList<ShaderData> shader_list_element;
ShaderData();
virtual ~ShaderData();
};
SelfList<ShaderData>::List shader_list;
RendererRD::MaterialStorage::ShaderData *_create_shader_func();
static RendererRD::MaterialStorage::ShaderData *_create_shader_funcs() {
return static_cast<SceneShaderForwardClustered *>(singleton)->_create_shader_func();
}
struct MaterialData : public RendererRD::MaterialStorage::MaterialData {
ShaderData *shader_data = nullptr;
RID uniform_set;
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 bool update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual ~MaterialData();
};
RendererRD::MaterialStorage::MaterialData *_create_material_func(ShaderData *p_shader);
static RendererRD::MaterialStorage::MaterialData *_create_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader) {
return static_cast<SceneShaderForwardClustered *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
}
SceneForwardClusteredShaderRD shader;
ShaderCompiler compiler;
RID default_shader;
RID default_material;
RID overdraw_material_shader;
RID overdraw_material;
RID debug_shadow_splits_material_shader;
RID debug_shadow_splits_material;
RID default_shader_rd;
RID default_shader_sdfgi_rd;
RID default_vec4_xform_buffer;
RID default_vec4_xform_uniform_set;
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;
RID debug_shadow_splits_material_uniform_set;
ShaderData *debug_shadow_splits_material_shader_ptr = nullptr;
Vector<RD::PipelineSpecializationConstant> default_specialization_constants;
bool valid_color_pass_pipelines[PIPELINE_COLOR_PASS_FLAG_COUNT];
SceneShaderForwardClustered();
~SceneShaderForwardClustered();
void init(const String p_defines);
void set_default_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_constants);
void enable_advanced_shader_group(bool p_needs_multiview = false);
};
} // namespace RendererSceneRenderImplementation
#endif // SCENE_SHADER_FORWARD_CLUSTERED_H

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
Import("env")
env.add_source_files(env.servers_sources, "*.cpp")

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,591 @@
/**************************************************************************/
/* render_forward_mobile.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 RENDER_FORWARD_MOBILE_H
#define RENDER_FORWARD_MOBILE_H
#include "core/templates/paged_allocator.h"
#include "servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/utilities.h"
#define RB_SCOPE_MOBILE SNAME("mobile")
namespace RendererSceneRenderImplementation {
class RenderForwardMobile : public RendererSceneRenderRD {
friend SceneShaderForwardMobile;
protected:
struct GeometryInstanceSurfaceDataCache;
private:
static RenderForwardMobile *singleton;
/* Scene Shader */
enum {
SCENE_UNIFORM_SET = 0,
RENDER_PASS_UNIFORM_SET = 1,
TRANSFORMS_UNIFORM_SET = 2,
MATERIAL_UNIFORM_SET = 3,
};
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,
SPEC_CONSTANT_USE_DEPTH_FOG = 16,
SPEC_CONSTANT_IS_MULTIMESH = 17,
};
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
};
enum RenderListType {
RENDER_LIST_OPAQUE, //used for opaque objects
RENDER_LIST_ALPHA, //used for transparent objects
RENDER_LIST_SECONDARY, //used for shadows and other objects
RENDER_LIST_MAX
};
/* Scene Shader */
SceneShaderForwardMobile scene_shader;
/* Render Buffer */
class RenderBufferDataForwardMobile : public RenderBufferCustomDataRD {
GDCLASS(RenderBufferDataForwardMobile, RenderBufferCustomDataRD);
public:
enum FramebufferConfigType {
FB_CONFIG_RENDER_PASS, // Single pass framebuffer for normal rendering.
FB_CONFIG_RENDER_AND_POST_PASS, // Two subpasses, one for normal rendering, one for post processing.
FB_CONFIG_MAX
};
RID get_color_fbs(FramebufferConfigType p_config_type);
virtual void free_data() override;
virtual void configure(RenderSceneBuffersRD *p_render_buffers) override;
private:
RenderSceneBuffersRD *render_buffers = nullptr;
};
virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) override;
/* Rendering */
enum PassMode {
PASS_MODE_COLOR,
// PASS_MODE_COLOR_SPECULAR,
PASS_MODE_COLOR_TRANSPARENT,
PASS_MODE_SHADOW,
PASS_MODE_SHADOW_DP,
// PASS_MODE_DEPTH,
// PASS_MODE_DEPTH_NORMAL_ROUGHNESS,
// PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI,
PASS_MODE_DEPTH_MATERIAL,
// PASS_MODE_SDF,
};
struct RenderElementInfo;
struct RenderListParameters {
GeometryInstanceSurfaceDataCache **elements = nullptr;
RenderElementInfo *element_info = nullptr;
int element_count = 0;
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;
uint32_t spec_constant_base_flags = 0;
float lod_distance_multiplier = 0.0;
float screen_mesh_lod_threshold = 0.0;
RD::FramebufferFormatID framebuffer_format = 0;
uint32_t element_offset = 0;
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, uint32_t p_spec_constant_base_flags = 0, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0) {
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;
lod_distance_multiplier = p_lod_distance_multiplier;
screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
element_offset = p_element_offset;
spec_constant_base_flags = p_spec_constant_base_flags;
}
};
/* Render shadows */
void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Transform3D &p_main_cam_transform = Transform3D());
void _render_shadow_begin();
void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &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, float p_lod_distance_multiplier = 0.0, float p_screen_mesh_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, RenderingMethod::RenderInfo *p_render_info = nullptr, const Transform3D &p_main_cam_transform = Transform3D());
void _render_shadow_process();
void _render_shadow_end();
/* Render Scene */
RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, const RendererRD::MaterialStorage::Samplers &p_samplers, bool p_use_directional_shadow_atlas = false, int p_index = 0);
void _pre_opaque_render(RenderDataRD *p_render_data);
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
void _update_render_base_uniform_set();
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_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false);
void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, 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 RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
RID render_base_uniform_set;
LocalVector<RID> render_pass_uniform_sets;
/* Light map */
struct LightmapData {
float normal_xform[12];
float pad[3];
float exposure_normalization;
};
struct LightmapCaptureData {
float sh[9 * 4];
};
/* Scene state */
struct SceneState {
LocalVector<RID> uniform_buffers;
struct PushConstant {
float uv_offset[2];
uint32_t base_index;
uint32_t pad;
};
struct InstanceData {
float transform[16];
uint32_t flags;
uint32_t instance_uniforms_ofs; // Base offset in global buffer for instance variables.
uint32_t gi_offset; // GI information when using lightmapping (VCT or lightmap index).
uint32_t layer_mask = 1;
float lightmap_uv_scale[4]; // Doubles as uv_offset when needed.
uint32_t reflection_probes[2]; // Packed reflection probes.
uint32_t omni_lights[2]; // Packed omni lights.
uint32_t spot_lights[2]; // Packed spot lights.
uint32_t decals[2]; // Packed spot lights.
float compressed_aabb_position[4];
float compressed_aabb_size[4];
float uv_scale[4];
};
RID instance_buffer[RENDER_LIST_MAX];
uint32_t instance_buffer_size[RENDER_LIST_MAX] = { 0, 0, 0 };
LocalVector<InstanceData> instance_data[RENDER_LIST_MAX];
// !BAS! We need to change lightmaps, we're not going to do this with a buffer but pushing the used lightmap in
LightmapData lightmaps[MAX_LIGHTMAPS];
RID lightmap_ids[MAX_LIGHTMAPS];
bool lightmap_has_sh[MAX_LIGHTMAPS];
uint32_t lightmaps_used = 0;
uint32_t max_lightmaps;
RID lightmap_buffer;
LightmapCaptureData *lightmap_captures = nullptr;
uint32_t max_lightmap_captures;
RID lightmap_capture_buffer;
bool used_screen_texture = false;
bool used_normal_texture = false;
bool used_depth_texture = false;
bool used_sss = false;
struct ShadowPass {
uint32_t element_from;
uint32_t element_count;
bool flip_cull;
PassMode pass_mode;
RID rp_uniform_set;
float lod_distance_multiplier;
float screen_mesh_lod_threshold;
RID framebuffer;
RD::InitialAction initial_depth_action;
Rect2i rect;
};
LocalVector<ShadowPass> shadow_passes;
} scene_state;
/* Render List */
// !BAS! Render list can probably be reused between clustered and mobile?
struct RenderList {
LocalVector<GeometryInstanceSurfaceDataCache *> elements;
LocalVector<RenderElementInfo> element_info;
void clear() {
elements.clear();
element_info.clear();
}
//should eventually be replaced by radix
struct SortByKey {
_FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const {
return (A->sort.sort_key2 == B->sort.sort_key2) ? (A->sort.sort_key1 < B->sort.sort_key1) : (A->sort.sort_key2 < B->sort.sort_key2);
}
};
void sort_by_key() {
SortArray<GeometryInstanceSurfaceDataCache *, SortByKey> sorter;
sorter.sort(elements.ptr(), elements.size());
}
void sort_by_key_range(uint32_t p_from, uint32_t p_size) {
SortArray<GeometryInstanceSurfaceDataCache *, SortByKey> sorter;
sorter.sort(elements.ptr() + p_from, p_size);
}
struct SortByDepth {
_FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const {
return (A->owner->depth < B->owner->depth);
}
};
void sort_by_depth() { //used for shadows
SortArray<GeometryInstanceSurfaceDataCache *, SortByDepth> sorter;
sorter.sort(elements.ptr(), elements.size());
}
struct SortByReverseDepthAndPriority {
_FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const {
return (A->sort.priority == B->sort.priority) ? (A->owner->depth > B->owner->depth) : (A->sort.priority < B->sort.priority);
}
};
void sort_by_reverse_depth_and_priority() { //used for alpha
SortArray<GeometryInstanceSurfaceDataCache *, SortByReverseDepthAndPriority> sorter;
sorter.sort(elements.ptr(), elements.size());
}
_FORCE_INLINE_ void add_element(GeometryInstanceSurfaceDataCache *p_element) {
elements.push_back(p_element);
}
};
struct RenderElementInfo {
uint32_t uses_lightmap : 1;
uint32_t lod_index : 8;
uint32_t reserved : 23;
};
template <PassMode p_pass_mode>
_FORCE_INLINE_ void _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);
void _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);
void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 0.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
RenderList render_list[RENDER_LIST_MAX];
protected:
/* setup */
virtual void _update_shader_quality_settings() override;
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;
virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) 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{};
virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override{};
virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override{};
virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override{};
virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override{};
/* Geometry instance */
class GeometryInstanceForwardMobile;
// When changing any of these enums, remember to change the corresponding enums in the shader files as well.
enum {
INSTANCE_DATA_FLAGS_DYNAMIC = 1 << 3,
INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,
INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 6,
INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 7,
INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 8,
INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 9,
INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 10,
INSTANCE_DATA_FLAG_PARTICLES = 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,
};
struct GeometryInstanceLightmapSH {
Color sh[9];
};
// Cached data for drawing surfaces
struct GeometryInstanceSurfaceDataCache {
enum {
FLAG_PASS_DEPTH = 1,
FLAG_PASS_OPAQUE = 2,
FLAG_PASS_ALPHA = 4,
FLAG_PASS_SHADOW = 8,
FLAG_USES_SHARED_SHADOW_MATERIAL = 128,
FLAG_USES_SUBSURFACE_SCATTERING = 2048,
FLAG_USES_SCREEN_TEXTURE = 4096,
FLAG_USES_DEPTH_TEXTURE = 8192,
FLAG_USES_NORMAL_TEXTURE = 16384,
FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768,
FLAG_USES_PARTICLE_TRAILS = 65536,
};
union {
struct {
// !BAS! CHECK BITS!!!
uint64_t surface_index : 10;
uint64_t geometry_id : 32;
uint64_t material_id_low : 16;
uint64_t material_id_hi : 16;
uint64_t shader_id : 32;
uint64_t uses_lightmap : 4; // sort by lightmap id here, not whether its yes/no (is 4 bits enough?)
uint64_t depth_layer : 4;
uint64_t priority : 8;
// uint64_t lod_index : 8; // no need to sort on LOD
// uint64_t uses_forward_gi : 1; // no GI here, remove
};
struct {
uint64_t sort_key1;
uint64_t sort_key2;
};
} sort;
RS::PrimitiveType primitive = RS::PRIMITIVE_MAX;
uint32_t flags = 0;
uint32_t surface_index = 0;
uint32_t lod_index = 0;
void *surface = nullptr;
RID material_uniform_set;
SceneShaderForwardMobile::ShaderData *shader = nullptr;
SceneShaderForwardMobile::MaterialData *material = nullptr;
void *surface_shadow = nullptr;
RID material_uniform_set_shadow;
SceneShaderForwardMobile::ShaderData *shader_shadow = nullptr;
GeometryInstanceSurfaceDataCache *next = nullptr;
GeometryInstanceForwardMobile *owner = nullptr;
};
class GeometryInstanceForwardMobile : public RenderGeometryInstanceBase {
public:
//used during rendering
RID transforms_uniform_set;
bool use_projector = false;
bool use_soft_shadow = false;
bool store_transform_cache = true; // If true we copy our transform into our per-draw buffer, if false we use our transforms UBO and clear our per-draw transform.
uint32_t instance_count = 0;
uint32_t trail_steps = 1;
// lightmap
uint32_t gi_offset_cache = 0; // !BAS! Should rename this to lightmap_offset_cache, in forward clustered this was shared between gi and lightmap
RID lightmap_instance;
Rect2 lightmap_uv_scale;
uint32_t lightmap_slice_index;
GeometryInstanceLightmapSH *lightmap_sh = nullptr;
// culled light info
uint32_t reflection_probe_count = 0;
RendererRD::ForwardID reflection_probes[MAX_RDL_CULL];
uint32_t omni_light_count = 0;
RendererRD::ForwardID omni_lights[MAX_RDL_CULL];
uint32_t spot_light_count = 0;
RendererRD::ForwardID spot_lights[MAX_RDL_CULL];
uint32_t decals_count = 0;
RendererRD::ForwardID decals[MAX_RDL_CULL];
GeometryInstanceSurfaceDataCache *surface_caches = nullptr;
// do we use this?
SelfList<GeometryInstanceForwardMobile> dirty_list_element;
GeometryInstanceForwardMobile() :
dirty_list_element(this) {}
virtual void _mark_dirty() override;
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override;
virtual void set_lightmap_capture(const Color *p_sh9) override;
virtual void pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) override;
virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override;
virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override;
virtual void pair_voxel_gi_instances(const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override {}
virtual void set_softshadow_projector_pairing(bool p_softshadow, bool p_projector) override;
};
/* Rendering */
virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) override;
virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
virtual void _render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) override;
virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) override;
/* Forward ID */
class ForwardIDStorageMobile : public RendererRD::ForwardIDStorage {
public:
struct ForwardIDAllocator {
LocalVector<bool> allocations;
LocalVector<uint8_t> map;
LocalVector<uint64_t> last_pass;
};
ForwardIDAllocator forward_id_allocators[RendererRD::FORWARD_ID_MAX];
public:
virtual RendererRD::ForwardID allocate_forward_id(RendererRD::ForwardIDType p_type) override;
virtual void free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) override;
virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index, uint64_t p_last_pass) override;
virtual bool uses_forward_ids() const override { return true; }
};
ForwardIDStorageMobile *forward_id_storage_mobile = nullptr;
void fill_push_constant_instance_indices(SceneState::InstanceData *p_instance_data, const GeometryInstanceForwardMobile *p_instance);
virtual RendererRD::ForwardIDStorage *create_forward_id_storage() override {
forward_id_storage_mobile = memnew(ForwardIDStorageMobile);
return forward_id_storage_mobile;
}
public:
static RenderForwardMobile *get_singleton() { return singleton; }
virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth) override;
/* SDFGI UPDATE */
virtual void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}
virtual int sdfgi_get_pending_region_count(const Ref<RenderSceneBuffers> &p_render_buffers) const override { return 0; }
virtual AABB sdfgi_get_pending_region_bounds(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override { return AABB(); }
virtual uint32_t sdfgi_get_pending_region_cascade(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override { return 0; }
/* GEOMETRY INSTANCE */
static void _geometry_instance_dependency_changed(Dependency::DependencyChangedNotification p_notification, DependencyTracker *p_tracker);
static void _geometry_instance_dependency_deleted(const RID &p_dependency, DependencyTracker *p_tracker);
SelfList<GeometryInstanceForwardMobile>::List geometry_instance_dirty_list;
PagedAllocator<GeometryInstanceForwardMobile> geometry_instance_alloc;
PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc;
PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh;
void _geometry_instance_add_surface_with_material(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh);
void _geometry_instance_add_surface_with_material_chain(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, RID p_mat_src, RID p_mesh);
void _geometry_instance_add_surface(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, RID p_material, RID p_mesh);
void _geometry_instance_update(RenderGeometryInstance *p_geometry_instance);
void _update_dirty_geometry_instances();
virtual RenderGeometryInstance *geometry_instance_create(RID p_base) override;
virtual void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) override;
virtual uint32_t geometry_instance_get_pair_mask() override;
virtual bool free(RID p_rid) override;
virtual void base_uniforms_changed() override;
virtual bool is_dynamic_gi_supported() const override;
virtual bool is_volumetric_supported() const override;
virtual uint32_t get_max_elements() const override;
RenderForwardMobile();
~RenderForwardMobile();
};
} // namespace RendererSceneRenderImplementation
#endif // RENDER_FORWARD_MOBILE_H

View file

@ -0,0 +1,780 @@
/**************************************************************************/
/* scene_shader_forward_mobile.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "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"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
using namespace RendererSceneRenderImplementation;
/* ShaderData */
void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
//compile
code = p_code;
valid = false;
ubo_size = 0;
uniforms.clear();
if (code.is_empty()) {
return; //just invalid, but no error
}
ShaderCompiler::GeneratedCode gen_code;
int blend_mode = BLEND_MODE_MIX;
int depth_testi = DEPTH_TEST_ENABLED;
int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
int cull = CULL_BACK;
uses_point_size = false;
uses_alpha = false;
uses_alpha_clip = false;
uses_alpha_antialiasing = false;
uses_blend_alpha = false;
uses_depth_prepass_alpha = false;
uses_discard = false;
uses_roughness = false;
uses_normal = false;
uses_tangent = false;
bool uses_normal_map = false;
bool wireframe = false;
unshaded = false;
uses_vertex = false;
uses_sss = false;
uses_transmittance = false;
uses_time = false;
writes_modelview_or_projection = false;
uses_world_coordinates = false;
uses_particle_trails = false;
int depth_drawi = DEPTH_DRAW_OPAQUE;
ShaderCompiler::IdentifierActions actions;
actions.entry_point_stages["vertex"] = ShaderCompiler::STAGE_VERTEX;
actions.entry_point_stages["fragment"] = ShaderCompiler::STAGE_FRAGMENT;
actions.entry_point_stages["light"] = ShaderCompiler::STAGE_FRAGMENT;
actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD);
actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PREMULT_ALPHA);
actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE);
actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED);
actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull, CULL_DISABLED);
actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull, CULL_FRONT);
actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull, CULL_BACK);
actions.render_mode_flags["unshaded"] = &unshaded;
actions.render_mode_flags["wireframe"] = &wireframe;
actions.render_mode_flags["particle_trails"] = &uses_particle_trails;
actions.render_mode_flags["world_vertex_coords"] = &uses_world_coordinates;
actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
actions.usage_flag_pointers["ALPHA_SCISSOR_THRESHOLD"] = &uses_alpha_clip;
actions.usage_flag_pointers["ALPHA_HASH_SCALE"] = &uses_alpha_clip;
actions.usage_flag_pointers["ALPHA_ANTIALIASING_EDGE"] = &uses_alpha_antialiasing;
actions.usage_flag_pointers["ALPHA_TEXTURE_COORDINATE"] = &uses_alpha_antialiasing;
actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_prepass_alpha;
actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance;
actions.usage_flag_pointers["DISCARD"] = &uses_discard;
actions.usage_flag_pointers["TIME"] = &uses_time;
actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness;
actions.usage_flag_pointers["NORMAL"] = &uses_normal;
actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal_map;
actions.usage_flag_pointers["TANGENT"] = &uses_tangent;
actions.usage_flag_pointers["BINORMAL"] = &uses_tangent;
actions.usage_flag_pointers["ANISOTROPY"] = &uses_tangent;
actions.usage_flag_pointers["ANISOTROPY_FLOW"] = &uses_tangent;
actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size;
actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size;
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.uniforms = &uniforms;
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = shader_singleton->shader.version_create();
}
depth_draw = DepthDraw(depth_drawi);
depth_test = DepthTest(depth_testi);
uses_vertex_time = gen_code.uses_vertex_time;
uses_fragment_time = gen_code.uses_fragment_time;
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
uses_screen_texture = gen_code.uses_screen_texture;
uses_depth_texture = gen_code.uses_depth_texture;
uses_normal_texture = gen_code.uses_normal_roughness_texture;
uses_normal |= uses_normal_map;
uses_tangent |= uses_normal_map;
#ifdef DEBUG_ENABLED
if (uses_sss) {
WARN_PRINT_ONCE_ED("Sub-surface scattering is only available when using the Forward+ rendering backend.");
}
if (uses_transmittance) {
WARN_PRINT_ONCE_ED("Transmittance is only available when using the Forward+ rendering backend.");
}
#endif
#if 0
print_line("**compiling shader:");
print_line("**defines:\n");
for (int i = 0; i < gen_code.defines.size(); i++) {
print_line(gen_code.defines[i]);
}
HashMap<String, String>::Iterator el = gen_code.code.begin();
while (el) {
print_line("\n**code " + el->key + ":\n" + el->value);
++el;
}
print_line("\n**uniforms:\n" + gen_code.uniforms);
print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]);
print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
#endif
shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines);
ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version));
ubo_size = gen_code.uniform_total_size;
ubo_offsets = gen_code.uniform_offsets;
texture_uniforms = gen_code.texture_uniforms;
//blend modes
// if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage
if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) {
blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE;
}
RD::PipelineColorBlendState::Attachment blend_attachment;
switch (blend_mode) {
case BLEND_MODE_MIX: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
} break;
case BLEND_MODE_ADD: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
uses_blend_alpha = true; //force alpha used because of blend
} break;
case BLEND_MODE_SUB: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_REVERSE_SUBTRACT;
blend_attachment.color_blend_op = RD::BLEND_OP_REVERSE_SUBTRACT;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
uses_blend_alpha = true; //force alpha used because of blend
} break;
case BLEND_MODE_MUL: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
uses_blend_alpha = true; //force alpha used because of blend
} break;
case BLEND_MODE_ALPHA_TO_COVERAGE: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
} break;
case BLEND_MODE_PREMULT_ALPHA: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
uses_blend_alpha = true; // Force alpha used because of blend.
} break;
}
RD::PipelineColorBlendState blend_state_blend;
blend_state_blend.attachments.push_back(blend_attachment);
RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1);
RD::PipelineColorBlendState blend_state_opaque_specular = RD::PipelineColorBlendState::create_disabled(2);
RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1);
RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2);
//update pipelines
RD::PipelineDepthStencilState depth_stencil_state;
if (depth_test != DEPTH_TEST_DISABLED) {
depth_stencil_state.enable_depth_test = true;
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
}
for (int i = 0; i < CULL_VARIANT_MAX; i++) {
RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = {
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK },
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT },
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED }
};
RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull];
for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
RD::RENDER_PRIMITIVE_POINTS,
RD::RENDER_PRIMITIVE_LINES,
RD::RENDER_PRIMITIVE_LINESTRIPS,
RD::RENDER_PRIMITIVE_TRIANGLES,
RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
};
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<SceneShaderForwardMobile *>(singleton)->shader.is_variant_enabled(k)) {
continue;
}
RD::PipelineRasterizationState raster_state;
raster_state.cull_mode = cull_mode_rd;
raster_state.wireframe = wireframe;
RD::PipelineColorBlendState blend_state;
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 (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) {
multisample_state.enable_alpha_to_coverage = true;
multisample_state.enable_alpha_to_one = true;
}
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 && !uses_alpha_clip) {
depth_stencil.enable_depth_write = false; //alpha does not draw depth
}
} 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
} 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_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_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 {
// ???
}
}
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, singleton->default_specialization_constants);
}
}
}
valid = true;
}
bool SceneShaderForwardMobile::ShaderData::is_animated() const {
return (uses_fragment_time && uses_discard) || (uses_vertex_time && uses_vertex);
}
bool SceneShaderForwardMobile::ShaderData::casts_shadows() const {
bool has_read_screen_alpha = uses_screen_texture || uses_depth_texture || uses_normal_texture;
bool has_base_alpha = (uses_alpha && (!uses_alpha_clip || uses_alpha_antialiasing)) || has_read_screen_alpha;
bool has_alpha = has_base_alpha || uses_blend_alpha;
return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED));
}
RS::ShaderNativeSourceCode SceneShaderForwardMobile::ShaderData::get_native_source_code() const {
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
return shader_singleton->shader.version_get_native_source_code(version);
}
SceneShaderForwardMobile::ShaderData::ShaderData() :
shader_list_element(this) {
}
SceneShaderForwardMobile::ShaderData::~ShaderData() {
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
ERR_FAIL_NULL(shader_singleton);
//pipeline variants will clear themselves if shader is gone
if (version.is_valid()) {
shader_singleton->shader.version_free(version);
}
}
RendererRD::MaterialStorage::ShaderData *SceneShaderForwardMobile::_create_shader_func() {
ShaderData *shader_data = memnew(ShaderData);
singleton->shader_list.add(&shader_data->shader_list_element);
return shader_data;
}
void SceneShaderForwardMobile::MaterialData::set_render_priority(int p_priority) {
priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits
}
void SceneShaderForwardMobile::MaterialData::set_next_pass(RID p_pass) {
next_pass = p_pass;
}
bool SceneShaderForwardMobile::MaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
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, true, true);
}
SceneShaderForwardMobile::MaterialData::~MaterialData() {
free_parameters_uniform_set(uniform_set);
}
RendererRD::MaterialStorage::MaterialData *SceneShaderForwardMobile::_create_material_func(ShaderData *p_shader) {
MaterialData *material_data = memnew(MaterialData);
material_data->shader_data = p_shader;
//update will happen later anyway so do nothing.
return material_data;
}
/* Scene Shader */
SceneShaderForwardMobile *SceneShaderForwardMobile::singleton = nullptr;
SceneShaderForwardMobile::SceneShaderForwardMobile() {
// there should be only one of these, contained within our RenderForwardMobile singleton.
singleton = this;
}
void SceneShaderForwardMobile::init(const String p_defines) {
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
/* SCENE SHADER */
{
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"); // 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::get_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);
}
}
material_storage->shader_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_3D, _create_shader_funcs);
material_storage->material_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_3D, _create_material_funcs);
{
//shader compiler
ShaderCompiler::DefaultIdentifierActions actions;
actions.renames["MODEL_MATRIX"] = "read_model_matrix";
actions.renames["MODEL_NORMAL_MATRIX"] = "model_normal_matrix";
actions.renames["VIEW_MATRIX"] = "read_view_matrix";
actions.renames["INV_VIEW_MATRIX"] = "inv_view_matrix";
actions.renames["PROJECTION_MATRIX"] = "projection_matrix";
actions.renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix";
actions.renames["MODELVIEW_MATRIX"] = "modelview";
actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal";
actions.renames["MAIN_CAM_INV_VIEW_MATRIX"] = "scene_data.main_cam_inv_view_matrix";
actions.renames["VERTEX"] = "vertex";
actions.renames["NORMAL"] = "normal";
actions.renames["TANGENT"] = "tangent";
actions.renames["BINORMAL"] = "binormal";
actions.renames["POSITION"] = "position";
actions.renames["UV"] = "uv_interp";
actions.renames["UV2"] = "uv2_interp";
actions.renames["COLOR"] = "color_interp";
actions.renames["POINT_SIZE"] = "gl_PointSize";
actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
actions.renames["VERTEX_ID"] = "gl_VertexIndex";
actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold";
actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale";
actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge";
actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate";
//builtins
actions.renames["TIME"] = "scene_data_block.data.time";
actions.renames["EXPOSURE"] = "(1.0 / scene_data_block.data.emissive_exposure_normalization)";
actions.renames["PI"] = _MKSTR(Math_PI);
actions.renames["TAU"] = _MKSTR(Math_TAU);
actions.renames["E"] = _MKSTR(Math_E);
actions.renames["VIEWPORT_SIZE"] = "read_viewport_size";
actions.renames["FRAGCOORD"] = "gl_FragCoord";
actions.renames["FRONT_FACING"] = "gl_FrontFacing";
actions.renames["NORMAL_MAP"] = "normal_map";
actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth";
actions.renames["ALBEDO"] = "albedo";
actions.renames["ALPHA"] = "alpha";
actions.renames["PREMUL_ALPHA_FACTOR"] = "premul_alpha";
actions.renames["METALLIC"] = "metallic";
actions.renames["SPECULAR"] = "specular";
actions.renames["ROUGHNESS"] = "roughness";
actions.renames["RIM"] = "rim";
actions.renames["RIM_TINT"] = "rim_tint";
actions.renames["CLEARCOAT"] = "clearcoat";
actions.renames["CLEARCOAT_ROUGHNESS"] = "clearcoat_roughness";
actions.renames["ANISOTROPY"] = "anisotropy";
actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
actions.renames["SSS_STRENGTH"] = "sss_strength";
actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color";
actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth";
actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost";
actions.renames["BACKLIGHT"] = "backlight";
actions.renames["AO"] = "ao";
actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
actions.renames["EMISSION"] = "emission";
actions.renames["POINT_COORD"] = "gl_PointCoord";
actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
actions.renames["SCREEN_UV"] = "screen_uv";
actions.renames["DEPTH"] = "gl_FragDepth";
actions.renames["FOG"] = "fog";
actions.renames["RADIANCE"] = "custom_radiance";
actions.renames["IRRADIANCE"] = "custom_irradiance";
actions.renames["BONE_INDICES"] = "bone_attrib";
actions.renames["BONE_WEIGHTS"] = "weight_attrib";
actions.renames["CUSTOM0"] = "custom0_attrib";
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["LIGHT_VERTEX"] = "light_vertex";
actions.renames["NODE_POSITION_WORLD"] = "read_model_matrix[3].xyz";
actions.renames["CAMERA_POSITION_WORLD"] = "scene_data.inv_view_matrix[3].xyz";
actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.inv_view_matrix[2].xyz";
actions.renames["CAMERA_VISIBLE_LAYERS"] = "scene_data.camera_visible_layers";
actions.renames["NODE_POSITION_VIEW"] = "(scene_data.view_matrix * read_model_matrix)[3].xyz";
actions.renames["VIEW_INDEX"] = "ViewIndex";
actions.renames["VIEW_MONO_LEFT"] = "0";
actions.renames["VIEW_RIGHT"] = "1";
actions.renames["EYE_OFFSET"] = "eye_offset";
//for light
actions.renames["VIEW"] = "view";
actions.renames["SPECULAR_AMOUNT"] = "specular_amount";
actions.renames["LIGHT_COLOR"] = "light_color";
actions.renames["LIGHT_IS_DIRECTIONAL"] = "is_directional";
actions.renames["LIGHT"] = "light";
actions.renames["ATTENUATION"] = "attenuation";
actions.renames["DIFFUSE_LIGHT"] = "diffuse_light";
actions.renames["SPECULAR_LIGHT"] = "specular_light";
actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n";
actions.usage_defines["BINORMAL"] = "@TANGENT";
actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n";
actions.usage_defines["RIM_TINT"] = "@RIM";
actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n";
actions.usage_defines["CLEARCOAT_ROUGHNESS"] = "@CLEARCOAT";
actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n";
actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
actions.usage_defines["AO"] = "#define AO_USED\n";
actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
actions.usage_defines["UV"] = "#define UV_USED\n";
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_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";
actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
actions.usage_defines["LIGHT_VERTEX"] = "#define LIGHT_VERTEX_USED\n";
actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n";
actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n";
actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n";
actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE";
actions.usage_defines["PREMUL_ALPHA_FACTOR"] = "#define PREMUL_ALPHA_USED";
actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";
actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n";
actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n";
actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n";
actions.usage_defines["MODEL_MATRIX"] = "#define MODEL_MATRIX_USED\n";
actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
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_prepass_alpha"] = "#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_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n";
actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
actions.render_mode_defines["debug_shadow_splits"] = "#define DEBUG_DRAW_PSSM_SPLITS\n";
actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = RenderForwardMobile::MATERIAL_UNIFORM_SET;
actions.base_uniform_string = "material.";
actions.base_varying_index = 10;
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
actions.global_buffer_array_variable = "global_shader_uniforms.data";
actions.instance_uniform_index_variable = "instances.data[draw_call.instance_index].instance_uniforms_ofs";
actions.apply_luminance_multiplier = true; // apply luminance multiplier to screen texture
actions.check_multiview_samplers = RendererCompositorRD::get_singleton()->is_xr_enabled(); // Make sure we check sampling multiview textures.
compiler.initialize(actions);
}
{
//default material and shader
default_shader = material_storage->shader_allocate();
material_storage->shader_initialize(default_shader);
material_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 = material_storage->material_allocate();
material_storage->material_initialize(default_material);
material_storage->material_set_shader(default_material, default_shader);
MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(default_material, RendererRD::MaterialStorage::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 = material_storage->shader_allocate();
material_storage->shader_initialize(overdraw_material_shader);
// Use relatively low opacity so that more "layers" of overlapping objects can be distinguished.
material_storage->shader_set_code(overdraw_material_shader, R"(
// 3D editor Overdraw debug draw mode shader (Mobile).
shader_type spatial;
render_mode blend_add, unshaded, fog_disabled;
void fragment() {
ALBEDO = vec3(0.4, 0.8, 0.8);
ALPHA = 0.1;
}
)");
overdraw_material = material_storage->material_allocate();
material_storage->material_initialize(overdraw_material);
material_storage->material_set_shader(overdraw_material, overdraw_material_shader);
MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(overdraw_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
overdraw_material_shader_ptr = md->shader_data;
overdraw_material_uniform_set = md->uniform_set;
}
{
debug_shadow_splits_material_shader = material_storage->shader_allocate();
material_storage->shader_initialize(debug_shadow_splits_material_shader);
// Use relatively low opacity so that more "layers" of overlapping objects can be distinguished.
material_storage->shader_set_code(debug_shadow_splits_material_shader, R"(
// 3D debug shadow splits mode shader (Mobile).
shader_type spatial;
render_mode debug_shadow_splits, fog_disabled;
void fragment() {
ALBEDO = vec3(1.0, 1.0, 1.0);
}
)");
debug_shadow_splits_material = material_storage->material_allocate();
material_storage->material_initialize(debug_shadow_splits_material);
material_storage->material_set_shader(debug_shadow_splits_material, debug_shadow_splits_material_shader);
MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(debug_shadow_splits_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
debug_shadow_splits_material_shader_ptr = md->shader_data;
debug_shadow_splits_material_uniform_set = md->uniform_set;
}
{
default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256);
Vector<RD::Uniform> uniforms;
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(default_vec4_xform_buffer);
u.binding = 0;
uniforms.push_back(u);
default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RenderForwardMobile::TRANSFORMS_UNIFORM_SET);
}
{
RD::SamplerState sampler;
sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
sampler.enable_compare = true;
sampler.compare_op = RD::COMPARE_OP_GREATER;
shadow_sampler = RD::get_singleton()->sampler_create(sampler);
}
}
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() {
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
RD::get_singleton()->free(default_vec4_xform_buffer);
RD::get_singleton()->free(shadow_sampler);
material_storage->shader_free(overdraw_material_shader);
material_storage->shader_free(default_shader);
material_storage->shader_free(debug_shadow_splits_material_shader);
material_storage->material_free(overdraw_material);
material_storage->material_free(default_material);
material_storage->material_free(debug_shadow_splits_material);
}

View file

@ -0,0 +1,215 @@
/**************************************************************************/
/* scene_shader_forward_mobile.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 SCENE_SHADER_FORWARD_MOBILE_H
#define SCENE_SHADER_FORWARD_MOBILE_H
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
#include "servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl.gen.h"
namespace RendererSceneRenderImplementation {
class SceneShaderForwardMobile {
private:
static SceneShaderForwardMobile *singleton;
public:
enum ShaderVersion {
SHADER_VERSION_COLOR_PASS,
SHADER_VERSION_LIGHTMAP_COLOR_PASS,
SHADER_VERSION_SHADOW_PASS,
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
};
struct ShaderData : public RendererRD::MaterialStorage::ShaderData {
enum BlendMode { //used internally
BLEND_MODE_MIX,
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL,
BLEND_MODE_PREMULT_ALPHA,
BLEND_MODE_ALPHA_TO_COVERAGE
};
enum DepthDraw {
DEPTH_DRAW_DISABLED,
DEPTH_DRAW_OPAQUE,
DEPTH_DRAW_ALWAYS
};
enum DepthTest {
DEPTH_TEST_DISABLED,
DEPTH_TEST_ENABLED
};
enum Cull {
CULL_DISABLED,
CULL_FRONT,
CULL_BACK
};
enum CullVariant {
CULL_VARIANT_NORMAL,
CULL_VARIANT_REVERSED,
CULL_VARIANT_DOUBLE_SIDED,
CULL_VARIANT_MAX
};
enum AlphaAntiAliasing {
ALPHA_ANTIALIASING_OFF,
ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
};
bool valid = false;
RID version;
uint64_t vertex_input_mask = 0;
PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX];
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size = 0;
String code;
DepthDraw depth_draw;
DepthTest depth_test;
bool uses_point_size = false;
bool uses_alpha = false;
bool uses_blend_alpha = false;
bool uses_alpha_clip = false;
bool uses_alpha_antialiasing = false;
bool uses_depth_prepass_alpha = false;
bool uses_discard = false;
bool uses_roughness = false;
bool uses_normal = false;
bool uses_tangent = false;
bool uses_particle_trails = false;
bool unshaded = false;
bool uses_vertex = false;
bool uses_sss = false;
bool uses_transmittance = false;
bool uses_screen_texture = false;
bool uses_depth_texture = false;
bool uses_normal_texture = false;
bool uses_screen_texture_mipmaps = false;
bool uses_time = false;
bool uses_vertex_time = false;
bool uses_fragment_time = false;
bool writes_modelview_or_projection = false;
bool uses_world_coordinates = false;
uint64_t last_pass = 0;
uint32_t index = 0;
virtual void set_code(const String &p_Code);
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
SelfList<ShaderData> shader_list_element;
ShaderData();
virtual ~ShaderData();
};
RendererRD::MaterialStorage::ShaderData *_create_shader_func();
static RendererRD::MaterialStorage::ShaderData *_create_shader_funcs() {
return static_cast<SceneShaderForwardMobile *>(singleton)->_create_shader_func();
}
struct MaterialData : public RendererRD::MaterialStorage::MaterialData {
ShaderData *shader_data = nullptr;
RID uniform_set;
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 bool update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual ~MaterialData();
};
SelfList<ShaderData>::List shader_list;
RendererRD::MaterialStorage::MaterialData *_create_material_func(ShaderData *p_shader);
static RendererRD::MaterialStorage::MaterialData *_create_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader) {
return static_cast<SceneShaderForwardMobile *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
}
SceneForwardMobileShaderRD shader;
ShaderCompiler compiler;
RID default_shader;
RID default_material;
RID overdraw_material_shader;
RID overdraw_material;
RID debug_shadow_splits_material_shader;
RID debug_shadow_splits_material;
RID default_shader_rd;
RID default_vec4_xform_buffer;
RID default_vec4_xform_uniform_set;
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;
RID debug_shadow_splits_material_uniform_set;
ShaderData *debug_shadow_splits_material_shader_ptr = nullptr;
SceneShaderForwardMobile();
~SceneShaderForwardMobile();
Vector<RD::PipelineSpecializationConstant> default_specialization_constants;
void init(const String p_defines);
void set_default_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_constants);
};
} // namespace RendererSceneRenderImplementation
#endif // SCENE_SHADER_FORWARD_MOBILE_H

View file

@ -0,0 +1,87 @@
/**************************************************************************/
/* framebuffer_cache_rd.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "framebuffer_cache_rd.h"
FramebufferCacheRD *FramebufferCacheRD::singleton = nullptr;
void FramebufferCacheRD::_bind_methods() {
ClassDB::bind_static_method("FramebufferCacheRD", D_METHOD("get_cache_multipass", "textures", "passes", "views"), &FramebufferCacheRD::get_cache_multipass_array);
}
void FramebufferCacheRD::_invalidate(Cache *p_cache) {
if (p_cache->prev) {
p_cache->prev->next = p_cache->next;
} else {
// At beginning of table
uint32_t table_idx = p_cache->hash % HASH_TABLE_SIZE;
hash_table[table_idx] = p_cache->next;
}
if (p_cache->next) {
p_cache->next->prev = p_cache->prev;
}
cache_allocator.free(p_cache);
cache_instances_used--;
}
void FramebufferCacheRD::_framebuffer_invalidation_callback(void *p_userdata) {
singleton->_invalidate(reinterpret_cast<Cache *>(p_userdata));
}
RID FramebufferCacheRD::get_cache_multipass_array(const TypedArray<RID> &p_textures, const TypedArray<RDFramebufferPass> &p_passes, uint32_t p_views) {
Vector<RID> textures;
Vector<RD::FramebufferPass> passes;
for (int i = 0; i < p_textures.size(); i++) {
RID texture = p_textures[i];
textures.push_back(texture); // store even if NULL
}
for (int i = 0; i < p_passes.size(); i++) {
Ref<RDFramebufferPass> pass = p_passes[i];
if (pass.is_valid()) {
passes.push_back(pass->base);
}
}
return FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, p_views);
}
FramebufferCacheRD::FramebufferCacheRD() {
ERR_FAIL_COND(singleton != nullptr);
singleton = this;
}
FramebufferCacheRD::~FramebufferCacheRD() {
if (cache_instances_used > 0) {
ERR_PRINT("At exit: " + itos(cache_instances_used) + " framebuffer cache instance(s) still in use.");
}
}

View file

@ -0,0 +1,316 @@
/**************************************************************************/
/* framebuffer_cache_rd.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 FRAMEBUFFER_CACHE_RD_H
#define FRAMEBUFFER_CACHE_RD_H
#include "core/templates/local_vector.h"
#include "core/templates/paged_allocator.h"
#include "servers/rendering/rendering_device.h"
#include "servers/rendering/rendering_device_binds.h"
class FramebufferCacheRD : public Object {
GDCLASS(FramebufferCacheRD, Object)
struct Cache {
Cache *prev = nullptr;
Cache *next = nullptr;
uint32_t hash = 0;
RID cache;
LocalVector<RID> textures;
LocalVector<RD::FramebufferPass> passes;
uint32_t views = 0;
};
PagedAllocator<Cache> cache_allocator;
enum {
HASH_TABLE_SIZE = 16381 // Prime
};
Cache *hash_table[HASH_TABLE_SIZE] = {};
static _FORCE_INLINE_ uint32_t _hash_pass(const RD::FramebufferPass &p, uint32_t h) {
h = hash_murmur3_one_32(p.depth_attachment, h);
h = hash_murmur3_one_32(p.vrs_attachment, h);
h = hash_murmur3_one_32(p.color_attachments.size(), h);
for (int i = 0; i < p.color_attachments.size(); i++) {
h = hash_murmur3_one_32(p.color_attachments[i], h);
}
h = hash_murmur3_one_32(p.resolve_attachments.size(), h);
for (int i = 0; i < p.resolve_attachments.size(); i++) {
h = hash_murmur3_one_32(p.resolve_attachments[i], h);
}
h = hash_murmur3_one_32(p.preserve_attachments.size(), h);
for (int i = 0; i < p.preserve_attachments.size(); i++) {
h = hash_murmur3_one_32(p.preserve_attachments[i], h);
}
return h;
}
static _FORCE_INLINE_ bool _compare_pass(const RD::FramebufferPass &a, const RD::FramebufferPass &b) {
if (a.depth_attachment != b.depth_attachment) {
return false;
}
if (a.vrs_attachment != b.vrs_attachment) {
return false;
}
if (a.color_attachments.size() != b.color_attachments.size()) {
return false;
}
for (int i = 0; i < a.color_attachments.size(); i++) {
if (a.color_attachments[i] != b.color_attachments[i]) {
return false;
}
}
if (a.resolve_attachments.size() != b.resolve_attachments.size()) {
return false;
}
for (int i = 0; i < a.resolve_attachments.size(); i++) {
if (a.resolve_attachments[i] != b.resolve_attachments[i]) {
return false;
}
}
if (a.preserve_attachments.size() != b.preserve_attachments.size()) {
return false;
}
for (int i = 0; i < a.preserve_attachments.size(); i++) {
if (a.preserve_attachments[i] != b.preserve_attachments[i]) {
return false;
}
}
return true;
}
_FORCE_INLINE_ uint32_t _hash_rids(uint32_t h, const RID &arg) {
return hash_murmur3_one_64(arg.get_id(), h);
}
template <typename... Args>
uint32_t _hash_rids(uint32_t h, const RID &arg, Args... args) {
h = hash_murmur3_one_64(arg.get_id(), h);
return _hash_rids(h, args...);
}
_FORCE_INLINE_ bool _compare_args(uint32_t idx, const LocalVector<RID> &textures, const RID &arg) {
return textures[idx] == arg;
}
template <typename... Args>
_FORCE_INLINE_ bool _compare_args(uint32_t idx, const LocalVector<RID> &textures, const RID &arg, Args... args) {
if (textures[idx] != arg) {
return false;
}
return _compare_args(idx + 1, textures, args...);
}
_FORCE_INLINE_ void _create_args(Vector<RID> &textures, const RID &arg) {
textures.push_back(arg);
}
template <typename... Args>
_FORCE_INLINE_ void _create_args(Vector<RID> &textures, const RID &arg, Args... args) {
textures.push_back(arg);
_create_args(textures, args...);
}
static FramebufferCacheRD *singleton;
uint32_t cache_instances_used = 0;
void _invalidate(Cache *p_cache);
static void _framebuffer_invalidation_callback(void *p_userdata);
RID _allocate_from_data(uint32_t p_views, uint32_t p_hash, uint32_t p_table_idx, const Vector<RID> &p_textures, const Vector<RD::FramebufferPass> &p_passes) {
RID rid;
if (p_passes.size()) {
rid = RD::get_singleton()->framebuffer_create_multipass(p_textures, p_passes, RD::INVALID_ID, p_views);
} else {
rid = RD::get_singleton()->framebuffer_create(p_textures, RD::INVALID_ID, p_views);
}
ERR_FAIL_COND_V(rid.is_null(), rid);
Cache *c = cache_allocator.alloc();
c->views = p_views;
c->cache = rid;
c->hash = p_hash;
c->textures.resize(p_textures.size());
for (uint32_t i = 0; i < c->textures.size(); i++) {
c->textures[i] = p_textures[i];
}
c->passes.resize(p_passes.size());
for (uint32_t i = 0; i < c->passes.size(); i++) {
c->passes[i] = p_passes[i];
}
c->prev = nullptr;
c->next = hash_table[p_table_idx];
if (hash_table[p_table_idx]) {
hash_table[p_table_idx]->prev = c;
}
hash_table[p_table_idx] = c;
RD::get_singleton()->framebuffer_set_invalidation_callback(rid, _framebuffer_invalidation_callback, c);
cache_instances_used++;
return rid;
}
private:
static void _bind_methods();
public:
template <typename... Args>
RID get_cache(Args... args) {
uint32_t h = hash_murmur3_one_32(1); //1 view
h = hash_murmur3_one_32(sizeof...(Args), h);
h = _hash_rids(h, args...);
h = hash_murmur3_one_32(0, h); // 0 passes
h = hash_fmix32(h);
uint32_t table_idx = h % HASH_TABLE_SIZE;
{
const Cache *c = hash_table[table_idx];
while (c) {
if (c->hash == h && c->passes.size() == 0 && c->textures.size() == sizeof...(Args) && c->views == 1 && _compare_args(0, c->textures, args...)) {
return c->cache;
}
c = c->next;
}
}
// Not in cache, create:
Vector<RID> textures;
_create_args(textures, args...);
return _allocate_from_data(1, h, table_idx, textures, Vector<RD::FramebufferPass>());
}
template <typename... Args>
RID get_cache_multiview(uint32_t p_views, Args... args) {
uint32_t h = hash_murmur3_one_32(p_views);
h = hash_murmur3_one_32(sizeof...(Args), h);
h = _hash_rids(h, args...);
h = hash_murmur3_one_32(0, h); // 0 passes
h = hash_fmix32(h);
uint32_t table_idx = h % HASH_TABLE_SIZE;
{
const Cache *c = hash_table[table_idx];
while (c) {
if (c->hash == h && c->passes.size() == 0 && c->textures.size() == sizeof...(Args) && c->views == p_views && _compare_args(0, c->textures, args...)) {
return c->cache;
}
c = c->next;
}
}
// Not in cache, create:
Vector<RID> textures;
_create_args(textures, args...);
return _allocate_from_data(p_views, h, table_idx, textures, Vector<RD::FramebufferPass>());
}
RID get_cache_multipass(const Vector<RID> &p_textures, const Vector<RD::FramebufferPass> &p_passes, uint32_t p_views = 1) {
uint32_t h = hash_murmur3_one_32(p_views);
h = hash_murmur3_one_32(p_textures.size(), h);
for (int i = 0; i < p_textures.size(); i++) {
h = hash_murmur3_one_64(p_textures[i].get_id(), h);
}
h = hash_murmur3_one_32(p_passes.size(), h);
for (int i = 0; i < p_passes.size(); i++) {
h = _hash_pass(p_passes[i], h);
}
h = hash_fmix32(h);
uint32_t table_idx = h % HASH_TABLE_SIZE;
{
const Cache *c = hash_table[table_idx];
while (c) {
if (c->hash == h && c->views == p_views && c->textures.size() == (uint32_t)p_textures.size() && c->passes.size() == (uint32_t)p_passes.size()) {
bool all_ok = true;
for (int i = 0; i < p_textures.size(); i++) {
if (p_textures[i] != c->textures[i]) {
all_ok = false;
break;
}
}
if (all_ok) {
for (int i = 0; i < p_passes.size(); i++) {
if (!_compare_pass(p_passes[i], c->passes[i])) {
all_ok = false;
break;
}
}
}
if (all_ok) {
return c->cache;
}
}
c = c->next;
}
}
// Not in cache, create:
return _allocate_from_data(p_views, h, table_idx, p_textures, p_passes);
}
static RID get_cache_multipass_array(const TypedArray<RID> &p_textures, const TypedArray<RDFramebufferPass> &p_passes, uint32_t p_views = 1);
static FramebufferCacheRD *get_singleton() { return singleton; }
FramebufferCacheRD();
~FramebufferCacheRD();
};
#endif // FRAMEBUFFER_CACHE_RD_H

View file

@ -0,0 +1,126 @@
/**************************************************************************/
/* pipeline_cache_rd.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "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, 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, p_render_pass);
bool wireframe = p_wireframe;
RD::PipelineRasterizationState raster_state_version = rasterization_state;
raster_state_version.wireframe = wireframe;
Vector<RD::PipelineSpecializationConstant> specialization_constants = base_specialization_constants;
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 = static_cast<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 = 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() {
// TODO: Clear should probably recompile all the variants already compiled instead to avoid stalls? Needs discussion.
if (versions) {
for (uint32_t i = 0; i < version_count; i++) {
//shader may be gone, so this may not be valid
if (RD::get_singleton()->render_pipeline_is_valid(versions[i].pipeline)) {
RD::get_singleton()->free(versions[i].pipeline);
}
}
version_count = 0;
memfree(versions);
versions = nullptr;
}
}
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;
input_mask = 0;
render_primitive = p_primitive;
rasterization_state = p_rasterization_state;
multisample_state = p_multisample;
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) {
ERR_FAIL_COND(p_shader.is_null());
_clear();
setup(p_shader, render_primitive, rasterization_state, multisample_state, depth_stencil_state, blend_state, dynamic_state_flags);
}
void PipelineCacheRD::clear() {
_clear();
shader = RID(); //clear shader
input_mask = 0;
}
PipelineCacheRD::PipelineCacheRD() {
version_count = 0;
versions = nullptr;
input_mask = 0;
}
PipelineCacheRD::~PipelineCacheRD() {
_clear();
}

View file

@ -0,0 +1,106 @@
/**************************************************************************/
/* pipeline_cache_rd.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 PIPELINE_CACHE_RD_H
#define PIPELINE_CACHE_RD_H
#include "core/os/spin_lock.h"
#include "servers/rendering/rendering_device.h"
class PipelineCacheRD {
SpinLock spin_lock;
RID shader;
uint64_t input_mask;
RD::RenderPrimitive render_primitive;
RD::PipelineRasterizationState rasterization_state;
RD::PipelineMultisampleState multisample_state;
RD::PipelineDepthStencilState depth_stencil_state;
RD::PipelineColorBlendState blend_state;
int dynamic_state_flags = 0;
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 = nullptr;
uint32_t version_count;
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, 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, 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),");
#endif
spin_lock.lock();
p_wireframe |= rasterization_state.wireframe;
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 && 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, p_render_pass, p_bool_specializations);
spin_lock.unlock();
return result;
}
_FORCE_INLINE_ uint64_t get_vertex_input_mask() {
if (input_mask == 0) {
ERR_FAIL_COND_V(shader.is_null(), 0);
input_mask = RD::get_singleton()->shader_get_vertex_input_attribute_mask(shader);
}
return input_mask;
}
void clear();
PipelineCacheRD();
~PipelineCacheRD();
};
#endif // PIPELINE_CACHE_RD_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,466 @@
/**************************************************************************/
/* renderer_canvas_render_rd.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 RENDERER_CANVAS_RENDER_RD_H
#define RENDERER_CANVAS_RENDER_RD_H
#include "servers/rendering/renderer_canvas_render.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/canvas.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/rendering_device.h"
#include "servers/rendering/shader_compiler.h"
class RendererCanvasRenderRD : public RendererCanvasRender {
enum {
BASE_UNIFORM_SET = 0,
MATERIAL_UNIFORM_SET = 1,
TRANSFORMS_UNIFORM_SET = 2,
CANVAS_TEXTURE_UNIFORM_SET = 3,
};
const int SAMPLERS_BINDING_FIRST_INDEX = 10;
enum ShaderVariant {
SHADER_VARIANT_QUAD,
SHADER_VARIANT_NINEPATCH,
SHADER_VARIANT_PRIMITIVE,
SHADER_VARIANT_PRIMITIVE_POINTS,
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES_POINTS,
SHADER_VARIANT_QUAD_LIGHT,
SHADER_VARIANT_NINEPATCH_LIGHT,
SHADER_VARIANT_PRIMITIVE_LIGHT,
SHADER_VARIANT_PRIMITIVE_POINTS_LIGHT,
SHADER_VARIANT_ATTRIBUTES_LIGHT,
SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT,
SHADER_VARIANT_MAX
};
enum {
FLAGS_INSTANCING_MASK = 0x7F,
FLAGS_INSTANCING_HAS_COLORS = (1 << 7),
FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 8),
FLAGS_CLIP_RECT_UV = (1 << 9),
FLAGS_TRANSPOSE_RECT = (1 << 10),
FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR = (1 << 11),
FLAGS_NINEPACH_DRAW_CENTER = (1 << 12),
FLAGS_USE_SKELETON = (1 << 15),
FLAGS_NINEPATCH_H_MODE_SHIFT = 16,
FLAGS_NINEPATCH_V_MODE_SHIFT = 18,
FLAGS_LIGHT_COUNT_SHIFT = 20,
FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 26),
FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 27),
FLAGS_USE_MSDF = (1 << 28),
FLAGS_USE_LCD = (1 << 29),
FLAGS_FLIP_H = (1 << 30),
FLAGS_FLIP_V = (1 << 31),
};
enum {
LIGHT_FLAGS_TEXTURE_MASK = 0xFFFF,
LIGHT_FLAGS_BLEND_SHIFT = 16,
LIGHT_FLAGS_BLEND_MASK = (3 << 16),
LIGHT_FLAGS_BLEND_MODE_ADD = (0 << 16),
LIGHT_FLAGS_BLEND_MODE_SUB = (1 << 16),
LIGHT_FLAGS_BLEND_MODE_MIX = (2 << 16),
LIGHT_FLAGS_BLEND_MODE_MASK = (3 << 16),
LIGHT_FLAGS_HAS_SHADOW = (1 << 20),
LIGHT_FLAGS_FILTER_SHIFT = 22
};
enum {
MAX_RENDER_ITEMS = 256 * 1024,
MAX_LIGHT_TEXTURES = 1024,
MAX_LIGHTS_PER_ITEM = 16,
DEFAULT_MAX_LIGHTS_PER_RENDER = 256
};
/****************/
/**** SHADER ****/
/****************/
enum PipelineVariant {
PIPELINE_VARIANT_QUAD,
PIPELINE_VARIANT_NINEPATCH,
PIPELINE_VARIANT_PRIMITIVE_TRIANGLES,
PIPELINE_VARIANT_PRIMITIVE_LINES,
PIPELINE_VARIANT_PRIMITIVE_POINTS,
PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES,
PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP,
PIPELINE_VARIANT_ATTRIBUTE_LINES,
PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP,
PIPELINE_VARIANT_ATTRIBUTE_POINTS,
PIPELINE_VARIANT_QUAD_LCD_BLEND,
PIPELINE_VARIANT_MAX
};
enum PipelineLightMode {
PIPELINE_LIGHT_MODE_DISABLED,
PIPELINE_LIGHT_MODE_ENABLED,
PIPELINE_LIGHT_MODE_MAX
};
struct PipelineVariants {
PipelineCacheRD variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX];
};
struct {
CanvasShaderRD canvas_shader;
RID default_version;
RID default_version_rd_shader;
RID quad_index_buffer;
RID quad_index_array;
PipelineVariants pipeline_variants;
ShaderCompiler compiler;
} shader;
struct CanvasShaderData : public RendererRD::MaterialStorage::ShaderData {
enum BlendMode { //used internally
BLEND_MODE_MIX,
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL,
BLEND_MODE_PMALPHA,
BLEND_MODE_DISABLED,
};
bool valid = false;
RID version;
PipelineVariants pipeline_variants;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size = 0;
String code;
bool uses_screen_texture = false;
bool uses_screen_texture_mipmaps = false;
bool uses_sdf = false;
bool uses_time = false;
virtual void set_code(const String &p_Code);
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
CanvasShaderData() {}
virtual ~CanvasShaderData();
};
RendererRD::MaterialStorage::ShaderData *_create_shader_func();
static RendererRD::MaterialStorage::ShaderData *_create_shader_funcs() {
return static_cast<RendererCanvasRenderRD *>(singleton)->_create_shader_func();
}
struct CanvasMaterialData : public RendererRD::MaterialStorage::MaterialData {
CanvasShaderData *shader_data = nullptr;
RID uniform_set;
RID uniform_set_srgb;
virtual void set_render_priority(int p_priority) {}
virtual void set_next_pass(RID p_pass) {}
virtual bool update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual ~CanvasMaterialData();
};
RendererRD::MaterialStorage::MaterialData *_create_material_func(CanvasShaderData *p_shader);
static RendererRD::MaterialStorage::MaterialData *_create_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader) {
return static_cast<RendererCanvasRenderRD *>(singleton)->_create_material_func(static_cast<CanvasShaderData *>(p_shader));
}
/**************************/
/**** CANVAS TEXTURES *****/
/**************************/
struct {
RS::CanvasItemTextureFilter default_filter;
RS::CanvasItemTextureRepeat default_repeat;
} default_samplers;
/******************/
/**** POLYGONS ****/
/******************/
struct PolygonBuffers {
RD::VertexFormatID vertex_format_id;
RID vertex_buffer;
RID vertex_array;
RID index_buffer;
RID indices;
uint32_t primitive_count = 0;
};
struct {
HashMap<PolygonID, PolygonBuffers> polygons;
PolygonID last_id;
} polygon_buffers;
/********************/
/**** PRIMITIVES ****/
/********************/
struct {
RID index_array[4];
} primitive_arrays;
/*******************/
/**** MATERIALS ****/
/*******************/
/******************/
/**** LIGHTING ****/
/******************/
struct CanvasLight {
RID texture;
struct {
bool enabled = false;
float z_far;
float y_offset;
Transform2D directional_xform;
} shadow;
};
RID_Owner<CanvasLight> canvas_light_owner;
struct ShadowRenderPushConstant {
float projection[16];
float modelview[8];
float direction[2];
float z_far;
float pad;
};
struct OccluderPolygon {
RS::CanvasOccluderPolygonCullMode cull_mode;
int line_point_count;
RID vertex_buffer;
RID vertex_array;
RID index_buffer;
RID index_array;
int sdf_point_count;
int sdf_index_count;
RID sdf_vertex_buffer;
RID sdf_vertex_array;
RID sdf_index_buffer;
RID sdf_index_array;
bool sdf_is_lines;
};
struct LightUniform {
float matrix[8]; //light to texture coordinate matrix
float shadow_matrix[8]; //light to shadow coordinate matrix
float color[4];
uint8_t shadow_color[4];
uint32_t flags; //index to light texture
float shadow_pixel_size;
float height;
float position[2];
float shadow_z_far_inv;
float shadow_y_ofs;
float atlas_rect[4];
};
RID_Owner<OccluderPolygon> occluder_polygon_owner;
enum ShadowRenderMode {
SHADOW_RENDER_MODE_SHADOW,
SHADOW_RENDER_MODE_SDF,
};
enum {
SHADOW_RENDER_SDF_TRIANGLES,
SHADOW_RENDER_SDF_LINES,
};
struct {
CanvasOcclusionShaderRD shader;
RID shader_version;
RID render_pipelines[3];
RID sdf_render_pipelines[2];
RD::VertexFormatID vertex_format;
RD::VertexFormatID sdf_vertex_format;
RD::FramebufferFormatID framebuffer_format;
RD::FramebufferFormatID sdf_framebuffer_format;
} shadow_render;
/***************/
/**** STATE ****/
/***************/
//state that does not vary across rendering all items
struct State {
//state buffer
struct Buffer {
float canvas_transform[16];
float screen_transform[16];
float canvas_normal_transform[16];
float canvas_modulate[4];
float screen_pixel_size[2];
float time;
uint32_t use_pixel_snap;
float sdf_to_tex[4];
float sdf_to_screen[2];
float screen_to_sdf[2];
uint32_t directional_light_count;
float tex_to_sdf;
uint32_t pad1;
uint32_t pad2;
};
LightUniform *light_uniforms = nullptr;
RID lights_uniform_buffer;
RID canvas_state_buffer;
RID shadow_sampler;
RID shadow_texture;
RID shadow_depth_texture;
RID shadow_fb;
int shadow_texture_size = 2048;
RID default_transforms_uniform_set;
uint32_t max_lights_per_render;
uint32_t max_lights_per_item;
double time;
} state;
struct PushConstant {
float world[6];
uint32_t flags;
uint32_t specular_shininess;
union {
//rect
struct {
float modulation[4];
union {
float msdf[4];
float ninepatch_margins[4];
};
float dst_rect[4];
float src_rect[4];
float pad[2];
};
//primitive
struct {
float points[6]; // vec2 points[3]
float uvs[6]; // vec2 points[3]
uint32_t colors[6]; // colors encoded as half
};
};
float color_texture_pixel_size[2];
uint32_t lights[4];
};
Item *items[MAX_RENDER_ITEMS];
bool using_directional_lights = false;
RID default_canvas_texture;
RID default_canvas_group_shader;
RID default_canvas_group_material;
RID default_clip_children_material;
RID default_clip_children_shader;
RS::CanvasItemTextureFilter default_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
RS::CanvasItemTextureRepeat default_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
RID _create_base_uniform_set(RID p_to_render_target, bool p_backbuffer);
bool debug_redraw = false;
Color debug_redraw_color;
double debug_redraw_time = 1.0;
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, bool p_texture_is_data = false); //recursive, so regular inline used instead.
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, bool &r_sdf_used, const Point2 &p_offset, RenderingMethod::RenderInfo *r_render_info = nullptr);
void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false, RenderingMethod::RenderInfo *r_render_info = nullptr);
_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 Transform3D &p_transform, float *p_mat4);
void _update_shadow_atlas();
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;
void free_polygon(PolygonID p_polygon) override;
RID light_create() override;
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;
virtual void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) override;
RID occluder_polygon_create() override;
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 canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_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, RenderingMethod::RenderInfo *r_render_info = nullptr) override;
virtual void set_shadow_texture_size(int p_size) override;
void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) override;
void set_time(double p_time);
void update() override;
bool free(RID p_rid) override;
RendererCanvasRenderRD();
~RendererCanvasRenderRD();
};
#endif // RENDERER_CANVAS_RENDER_RD_H

View file

@ -0,0 +1,338 @@
/**************************************************************************/
/* renderer_compositor_rd.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "renderer_compositor_rd.h"
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) {
Error err = RD::get_singleton()->screen_prepare_for_drawing(p_screen);
if (err != OK) {
// Window is minimized and does not have valid swapchain, skip drawing without printing errors.
return;
}
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(p_screen);
ERR_FAIL_COND(draw_list == RD::INVALID_ID);
for (int i = 0; i < p_amount; i++) {
RID rd_texture = texture_storage->render_target_get_rd_texture(p_render_targets[i].render_target);
ERR_CONTINUE(rd_texture.is_null());
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;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u.binding = 0;
u.append_id(blit.sampler);
u.append_id(rd_texture);
uniforms.push_back(u);
RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, blit.shader.version_get_shader(blit.shader_version, BLIT_MODE_NORMAL), 0);
render_target_descriptors[rd_texture] = uniform_set;
}
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);
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.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;
blit.push_constant.k1 = p_render_targets[i].lens_distortion.k1;
blit.push_constant.k2 = p_render_targets[i].lens_distortion.k2;
blit.push_constant.upscale = p_render_targets[i].lens_distortion.upscale;
blit.push_constant.aspect_ratio = p_render_targets[i].lens_distortion.aspect_ratio;
blit.push_constant.convert_to_srgb = texture_storage->render_target_is_using_hdr(p_render_targets[i].render_target);
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();
}
void RendererCompositorRD::begin_frame(double frame_step) {
frame++;
delta = frame_step;
time += frame_step;
double time_roll_over = GLOBAL_GET("rendering/limits/time/time_rollover_secs");
time = Math::fmod(time, time_roll_over);
canvas->set_time(time);
scene->set_time(time, frame_step);
}
void RendererCompositorRD::end_frame(bool p_swap_buffers) {
if (p_swap_buffers) {
RD::get_singleton()->swap_buffers();
}
}
void RendererCompositorRD::initialize() {
{
// Initialize blit
Vector<String> blit_modes;
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(DisplayServer::MAIN_WINDOW_ID), 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
Vector<uint8_t> pv;
pv.resize(6 * 2);
{
uint8_t *w = pv.ptrw();
uint16_t *p16 = (uint16_t *)w;
p16[0] = 0;
p16[1] = 1;
p16[2] = 2;
p16[3] = 0;
p16[4] = 2;
p16[5] = 3;
}
blit.index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT16, pv);
blit.array = RD::get_singleton()->index_array_create(blit.index_buffer, 0, 6);
blit.sampler = RD::get_singleton()->sampler_create(RD::SamplerState());
}
}
uint64_t RendererCompositorRD::frame = 1;
void RendererCompositorRD::finalize() {
memdelete(scene);
memdelete(canvas);
memdelete(fog);
memdelete(particles_storage);
memdelete(light_storage);
memdelete(mesh_storage);
memdelete(material_storage);
memdelete(texture_storage);
memdelete(utilities);
//only need to erase these, the rest are erased by cascade
blit.shader.version_free(blit.shader_version);
RD::get_singleton()->free(blit.index_buffer);
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) {
if (p_image.is_null() || p_image->is_empty()) {
return;
}
Error err = RD::get_singleton()->screen_prepare_for_drawing(DisplayServer::MAIN_WINDOW_ID);
if (err != OK) {
// Window is minimized and does not have valid swapchain, skip drawing without printing errors.
return;
}
RID texture = texture_storage->texture_allocate();
texture_storage->texture_2d_initialize(texture, p_image);
RID rd_texture = texture_storage->texture_get_rd_texture(texture, false);
RD::SamplerState sampler_state;
sampler_state.min_filter = p_use_filter ? RD::SAMPLER_FILTER_LINEAR : RD::SAMPLER_FILTER_NEAREST;
sampler_state.mag_filter = p_use_filter ? RD::SAMPLER_FILTER_LINEAR : RD::SAMPLER_FILTER_NEAREST;
sampler_state.max_lod = 0;
RID sampler = RD::get_singleton()->sampler_create(sampler_state);
RID uset;
{
Vector<RD::Uniform> uniforms;
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u.binding = 0;
u.append_id(sampler);
u.append_id(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;
blit.push_constant.convert_to_srgb = false;
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();
texture_storage->texture_free(texture);
RD::get_singleton()->free(sampler);
}
RendererCompositorRD *RendererCompositorRD::singleton = nullptr;
RendererCompositorRD::RendererCompositorRD() {
uniform_set_cache = memnew(UniformSetCacheRD);
framebuffer_cache = memnew(FramebufferCacheRD);
{
String shader_cache_dir = Engine::get_singleton()->get_shader_cache_path();
if (shader_cache_dir.is_empty()) {
shader_cache_dir = "user://";
}
Ref<DirAccess> da = DirAccess::open(shader_cache_dir);
if (da.is_null()) {
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.path_join("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.is_empty()) {
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);
}
}
}
}
ERR_FAIL_COND_MSG(singleton != nullptr, "A RendererCompositorRD singleton already exists.");
singleton = this;
utilities = memnew(RendererRD::Utilities);
texture_storage = memnew(RendererRD::TextureStorage);
material_storage = memnew(RendererRD::MaterialStorage);
mesh_storage = memnew(RendererRD::MeshStorage);
light_storage = memnew(RendererRD::LightStorage);
particles_storage = memnew(RendererRD::ParticlesStorage);
fog = memnew(RendererRD::Fog);
canvas = memnew(RendererCanvasRenderRD());
String rendering_method = OS::get_singleton()->get_current_rendering_method();
uint64_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
if (rendering_method == "mobile" || textures_per_stage < 48) {
if (rendering_method == "forward_plus") {
WARN_PRINT_ONCE("Platform supports less than 48 textures per stage which is less than required by the Clustered renderer. Defaulting to Mobile renderer.");
}
scene = memnew(RendererSceneRenderImplementation::RenderForwardMobile());
} else if (rendering_method == "forward_plus") {
scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered());
} else {
// Fall back to our high end renderer.
ERR_PRINT(vformat("Cannot instantiate RenderingDevice-based renderer with renderer type '%s'. Defaulting to Forward+ renderer.", rendering_method));
scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered());
}
scene->init();
}
RendererCompositorRD::~RendererCompositorRD() {
singleton = nullptr;
memdelete(uniform_set_cache);
memdelete(framebuffer_cache);
ShaderRD::set_shader_cache_dir(String());
}

View file

@ -0,0 +1,151 @@
/**************************************************************************/
/* renderer_compositor_rd.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 RENDERER_COMPOSITOR_RD_H
#define RENDERER_COMPOSITOR_RD_H
#include "core/os/os.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_rd/environment/fog.h"
#include "servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h"
#include "servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h"
#include "servers/rendering/renderer_rd/framebuffer_cache_rd.h"
#include "servers/rendering/renderer_rd/renderer_canvas_render_rd.h"
#include "servers/rendering/renderer_rd/shaders/blit.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/light_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/mesh_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/particles_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/utilities.h"
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
class RendererCompositorRD : public RendererCompositor {
protected:
UniformSetCacheRD *uniform_set_cache = nullptr;
FramebufferCacheRD *framebuffer_cache = nullptr;
RendererCanvasRenderRD *canvas = nullptr;
RendererRD::Utilities *utilities = nullptr;
RendererRD::LightStorage *light_storage = nullptr;
RendererRD::MaterialStorage *material_storage = nullptr;
RendererRD::MeshStorage *mesh_storage = nullptr;
RendererRD::ParticlesStorage *particles_storage = nullptr;
RendererRD::TextureStorage *texture_storage = nullptr;
RendererRD::Fog *fog = nullptr;
RendererSceneRenderRD *scene = nullptr;
enum BlitMode {
BLIT_MODE_NORMAL,
BLIT_MODE_USE_LAYER,
BLIT_MODE_LENS,
BLIT_MODE_NORMAL_ALPHA,
BLIT_MODE_MAX
};
struct BlitPushConstant {
float src_rect[4];
float dst_rect[4];
float eye_center[2];
float k1;
float k2;
float upscale;
float aspect_ratio;
uint32_t layer;
uint32_t convert_to_srgb;
};
struct Blit {
BlitPushConstant push_constant;
BlitShaderRD shader;
RID shader_version;
RID pipelines[BLIT_MODE_MAX];
RID index_buffer;
RID array;
RID sampler;
} blit;
HashMap<RID, RID> render_target_descriptors;
double time = 0.0;
double delta = 0.0;
static uint64_t frame;
static RendererCompositorRD *singleton;
public:
RendererUtilities *get_utilities() { return utilities; };
RendererLightStorage *get_light_storage() { return light_storage; }
RendererMaterialStorage *get_material_storage() { return material_storage; }
RendererMeshStorage *get_mesh_storage() { return mesh_storage; }
RendererParticlesStorage *get_particles_storage() { return particles_storage; }
RendererTextureStorage *get_texture_storage() { return texture_storage; }
RendererGI *get_gi() {
ERR_FAIL_NULL_V(scene, nullptr);
return scene->get_gi();
}
RendererFog *get_fog() { return fog; }
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 initialize();
void begin_frame(double frame_step);
void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount);
void gl_end_frame(bool p_swap_buffers) {}
void end_frame(bool p_swap_buffers);
void finalize();
_ALWAYS_INLINE_ uint64_t get_frame_number() const { return frame; }
_ALWAYS_INLINE_ double get_frame_delta_time() const { return delta; }
_ALWAYS_INLINE_ double get_total_time() const { return time; }
static Error is_viable() {
return OK;
}
static RendererCompositor *_create_current() {
return memnew(RendererCompositorRD);
}
static void make_current() {
_create_func = _create_current;
low_end = false;
}
static RendererCompositorRD *get_singleton() { return singleton; }
RendererCompositorRD();
~RendererCompositorRD();
};
#endif // RENDERER_COMPOSITOR_RD_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,341 @@
/**************************************************************************/
/* renderer_scene_render_rd.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 RENDERER_SCENE_RENDER_RD_H
#define RENDERER_SCENE_RENDER_RD_H
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
#include "servers/rendering/renderer_rd/effects/bokeh_dof.h"
#include "servers/rendering/renderer_rd/effects/copy_effects.h"
#include "servers/rendering/renderer_rd/effects/debug_effects.h"
#include "servers/rendering/renderer_rd/effects/fsr.h"
#include "servers/rendering/renderer_rd/effects/luminance.h"
#include "servers/rendering/renderer_rd/effects/tone_mapper.h"
#include "servers/rendering/renderer_rd/effects/vrs.h"
#include "servers/rendering/renderer_rd/environment/fog.h"
#include "servers/rendering/renderer_rd/environment/gi.h"
#include "servers/rendering/renderer_rd/environment/sky.h"
#include "servers/rendering/renderer_rd/framebuffer_cache_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/light_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/render_data_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
#include "servers/rendering/rendering_method.h"
class RendererSceneRenderRD : public RendererSceneRender {
friend RendererRD::SkyRD;
friend RendererRD::GI;
protected:
RendererRD::ForwardIDStorage *forward_id_storage = nullptr;
RendererRD::BokehDOF *bokeh_dof = nullptr;
RendererRD::CopyEffects *copy_effects = nullptr;
RendererRD::DebugEffects *debug_effects = nullptr;
RendererRD::Luminance *luminance = nullptr;
RendererRD::ToneMapper *tone_mapper = nullptr;
RendererRD::FSR *fsr = nullptr;
RendererRD::VRS *vrs = nullptr;
double time = 0.0;
double time_step = 0.0;
/* ENVIRONMENT */
bool glow_bicubic_upscale = false;
bool use_physical_light_units = false;
////////////////////////////////
virtual RendererRD::ForwardIDStorage *create_forward_id_storage() { return memnew(RendererRD::ForwardIDStorage); };
void _update_vrs(Ref<RenderSceneBuffersRD> p_render_buffers);
virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0;
virtual void _render_buffers_debug_draw(const RenderDataRD *p_render_data);
virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) = 0;
virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
virtual void _render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) = 0;
virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) = 0;
void _debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, uint32_t p_view_count, const Projection *p_camera_with_transforms);
virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
bool _needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi);
void _post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi);
bool _compositor_effects_has_flag(const RenderDataRD *p_render_data, RS::CompositorEffectFlags p_flag, RS::CompositorEffectCallbackType p_callback_type = RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_ANY);
bool _has_compositor_effect(RS::CompositorEffectCallbackType p_callback_type, const RenderDataRD *p_render_data);
void _process_compositor_effects(RS::CompositorEffectCallbackType p_callback_type, const RenderDataRD *p_render_data);
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<RenderGeometryInstance *> cull_argument_pool;
PagedArray<RenderGeometryInstance *> cull_argument; //need this to exist
RendererRD::SkyRD sky;
RendererRD::GI gi;
virtual void _update_shader_quality_settings() {}
static bool _debug_draw_can_use_effects(RS::ViewportDebugDraw p_debug_draw);
private:
RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
static RendererSceneRenderRD *singleton;
/* Shadow atlas */
RS::ShadowQuality shadows_quality = RS::SHADOW_QUALITY_MAX; //So it always updates when first set
RS::ShadowQuality directional_shadow_quality = RS::SHADOW_QUALITY_MAX;
float shadows_quality_radius = 1.0;
float directional_shadow_quality_radius = 1.0;
float *directional_penumbra_shadow_kernel = nullptr;
float *directional_soft_shadow_kernel = nullptr;
float *penumbra_shadow_kernel = nullptr;
float *soft_shadow_kernel = nullptr;
int directional_penumbra_shadow_samples = 0;
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;
/* RENDER BUFFERS */
/* GI */
bool screen_space_roughness_limiter = false;
float screen_space_roughness_limiter_amount = 0.25;
float screen_space_roughness_limiter_limit = 0.18;
/* Light data */
uint64_t scene_pass = 0;
uint32_t max_cluster_elements = 512;
/* Volumetric Fog */
uint32_t volumetric_fog_size = 128;
uint32_t volumetric_fog_depth = 128;
bool volumetric_fog_filter_active = true;
public:
static RendererSceneRenderRD *get_singleton() { return singleton; }
/* LIGHTING */
virtual void setup_added_reflection_probe(const Transform3D &p_transform, const Vector3 &p_half_size){};
virtual void setup_added_light(const RS::LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture){};
virtual void setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_size){};
/* GI */
RendererRD::GI *get_gi() { return &gi; }
/* SKY */
RendererRD::SkyRD *get_sky() { return &sky; }
/* SKY API */
virtual RID sky_allocate() override;
virtual void sky_initialize(RID p_rid) override;
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 void environment_glow_set_use_bicubic_upscale(bool p_enable) override;
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;
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;
virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override;
_FORCE_INLINE_ bool is_using_physical_light_units() {
return use_physical_light_units;
}
/* REFLECTION PROBE */
virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth);
/* FOG VOLUMES */
uint32_t get_volumetric_fog_size() const { return volumetric_fog_size; }
uint32_t get_volumetric_fog_depth() const { return volumetric_fog_depth; }
bool get_volumetric_fog_filter_active() const { return volumetric_fog_filter_active; }
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;
/* gi light probes */
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<RenderGeometryInstance *> &p_dynamic_objects) override;
virtual void voxel_gi_set_quality(RS::VoxelGIQuality p_quality) override { gi.voxel_gi_quality = p_quality; }
/* render buffers */
virtual float _render_buffers_get_luminance_multiplier();
virtual RD::DataFormat _render_buffers_get_color_format();
virtual bool _render_buffers_can_be_storage();
virtual Ref<RenderSceneBuffers> render_buffers_create() override;
virtual void gi_set_use_half_resolution(bool p_enable) override;
RID render_buffers_get_default_voxel_gi_buffer();
virtual void base_uniforms_changed() = 0;
virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &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_attributes, RID p_compositor, 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_mesh_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, RenderingMethod::RenderInfo *r_render_info = nullptr) override;
virtual void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
virtual void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) override;
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) 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 positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
virtual void directional_soft_shadow_filter_set_quality(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;
_FORCE_INLINE_ RS::ShadowQuality shadows_quality_get() const {
return shadows_quality;
}
_FORCE_INLINE_ RS::ShadowQuality directional_shadow_quality_get() const {
return directional_shadow_quality;
}
_FORCE_INLINE_ float shadows_quality_radius_get() const {
return shadows_quality_radius;
}
_FORCE_INLINE_ float directional_shadow_quality_radius_get() const {
return directional_shadow_quality_radius;
}
_FORCE_INLINE_ float *directional_penumbra_shadow_kernel_get() {
return directional_penumbra_shadow_kernel;
}
_FORCE_INLINE_ float *directional_soft_shadow_kernel_get() {
return directional_soft_shadow_kernel;
}
_FORCE_INLINE_ float *penumbra_shadow_kernel_get() {
return penumbra_shadow_kernel;
}
_FORCE_INLINE_ float *soft_shadow_kernel_get() {
return soft_shadow_kernel;
}
_FORCE_INLINE_ int directional_penumbra_shadow_samples_get() const {
return directional_penumbra_shadow_samples;
}
_FORCE_INLINE_ int directional_soft_shadow_samples_get() const {
return directional_soft_shadow_samples;
}
_FORCE_INLINE_ int penumbra_shadow_samples_get() const {
return penumbra_shadow_samples;
}
_FORCE_INLINE_ int soft_shadow_samples_get() const {
return soft_shadow_samples;
}
_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 TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) override;
virtual bool free(RID p_rid) override;
virtual void update() override;
virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override;
_FORCE_INLINE_ RS::ViewportDebugDraw get_debug_draw_mode() const {
return debug_draw;
}
virtual void set_time(double p_time, double p_step) override;
virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override;
virtual bool is_vrs_supported() const;
virtual bool is_dynamic_gi_supported() const;
virtual bool is_volumetric_supported() const;
virtual uint32_t get_max_elements() const;
void init();
RendererSceneRenderRD();
~RendererSceneRenderRD();
};
#endif // RENDERER_SCENE_RENDER_RD_H

View file

@ -0,0 +1,851 @@
/**************************************************************************/
/* shader_rd.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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_rd.h"
#include "core/io/compression.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/object/worker_thread_pool.h"
#include "core/version.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");
String text;
for (int i = 0; i < lines.size(); i++) {
const String &l = lines[i];
bool push_chunk = false;
StageTemplate::Chunk chunk;
if (l.begins_with("#VERSION_DEFINES")) {
chunk.type = StageTemplate::Chunk::TYPE_VERSION_DEFINES;
push_chunk = true;
} else if (l.begins_with("#GLOBALS")) {
switch (p_stage_type) {
case STAGE_TYPE_VERTEX:
chunk.type = StageTemplate::Chunk::TYPE_VERTEX_GLOBALS;
break;
case STAGE_TYPE_FRAGMENT:
chunk.type = StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS;
break;
case STAGE_TYPE_COMPUTE:
chunk.type = StageTemplate::Chunk::TYPE_COMPUTE_GLOBALS;
break;
default: {
}
}
push_chunk = true;
} else if (l.begins_with("#MATERIAL_UNIFORMS")) {
chunk.type = StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS;
push_chunk = true;
} else if (l.begins_with("#CODE")) {
chunk.type = StageTemplate::Chunk::TYPE_CODE;
push_chunk = true;
chunk.code = l.replace_first("#CODE", String()).replace(":", "").strip_edges().to_upper();
} else {
text += l + "\n";
}
if (push_chunk) {
if (!text.is_empty()) {
StageTemplate::Chunk text_chunk;
text_chunk.type = StageTemplate::Chunk::TYPE_TEXT;
text_chunk.text = text.utf8();
stage_templates[p_stage_type].chunks.push_back(text_chunk);
text = String();
}
stage_templates[p_stage_type].chunks.push_back(chunk);
}
}
if (!text.is_empty()) {
StageTemplate::Chunk text_chunk;
text_chunk.type = StageTemplate::Chunk::TYPE_TEXT;
text_chunk.text = text.utf8();
stage_templates[p_stage_type].chunks.push_back(text_chunk);
text = String();
}
}
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;
} else {
is_compute = false;
if (p_vertex_code) {
_add_stage(p_vertex_code, STAGE_TYPE_VERTEX);
}
if (p_fragment_code) {
_add_stage(p_fragment_code, STAGE_TYPE_FRAGMENT);
}
}
StringBuilder tohash;
tohash.append("[GodotVersionNumber]");
tohash.append(VERSION_NUMBER);
tohash.append("[GodotVersionHash]");
tohash.append(VERSION_HASH);
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() {
//initialize() was never called
ERR_FAIL_COND_V(group_to_variant_map.is_empty(), RID());
Version version;
version.dirty = true;
version.valid = false;
version.initialize_needed = true;
version.variants = nullptr;
return version_owner.make_rid(version);
}
void ShaderRD::_initialize_version(Version *p_version) {
_clear_version(p_version);
p_version->valid = false;
p_version->dirty = false;
p_version->variants = memnew_arr(RID, variant_defines.size());
}
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++) {
if (p_version->variants[i].is_valid()) {
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;
}
}
void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template) {
for (const StageTemplate::Chunk &chunk : p_template.chunks) {
switch (chunk.type) {
case StageTemplate::Chunk::TYPE_VERSION_DEFINES: {
builder.append("\n"); //make sure defines begin at newline
builder.append(general_defines.get_data());
builder.append(variant_defines[p_variant].text.get_data());
for (int j = 0; j < p_version->custom_defines.size(); j++) {
builder.append(p_version->custom_defines[j].get_data());
}
builder.append("\n"); //make sure defines begin at newline
if (p_version->uniforms.size()) {
builder.append("#define MATERIAL_UNIFORMS_USED\n");
}
for (const KeyValue<StringName, CharString> &E : p_version->code_sections) {
builder.append(String("#define ") + String(E.key) + "_CODE_USED\n");
}
#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
builder.append("#define MOLTENVK_USED\n");
#endif
builder.append(String("#define RENDER_DRIVER_") + OS::get_singleton()->get_current_rendering_driver_name().to_upper() + "\n");
} break;
case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: {
builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
} break;
case StageTemplate::Chunk::TYPE_VERTEX_GLOBALS: {
builder.append(p_version->vertex_globals.get_data()); // vertex globals
} break;
case StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS: {
builder.append(p_version->fragment_globals.get_data()); // fragment globals
} break;
case StageTemplate::Chunk::TYPE_COMPUTE_GLOBALS: {
builder.append(p_version->compute_globals.get_data()); // compute globals
} break;
case StageTemplate::Chunk::TYPE_CODE: {
if (p_version->code_sections.has(chunk.code)) {
builder.append(p_version->code_sections[chunk.code].get_data());
}
} break;
case StageTemplate::Chunk::TYPE_TEXT: {
builder.append(chunk.text.get_data());
} break;
}
}
}
void ShaderRD::_compile_variant(uint32_t p_variant, const CompileData *p_data) {
uint32_t variant = group_to_variant_map[p_data->group][p_variant];
if (!variants_enabled[variant]) {
return; // Variant is disabled, return.
}
Vector<RD::ShaderStageSPIRVData> stages;
String error;
String current_source;
RD::ShaderStage current_stage = RD::SHADER_STAGE_VERTEX;
bool build_ok = true;
if (!is_compute) {
//vertex stage
StringBuilder builder;
_build_variant_code(builder, variant, p_data->version, stage_templates[STAGE_TYPE_VERTEX]);
current_source = builder.as_string();
RD::ShaderStageSPIRVData stage;
stage.spirv = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_VERTEX, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
if (stage.spirv.size() == 0) {
build_ok = false;
} else {
stage.shader_stage = RD::SHADER_STAGE_VERTEX;
stages.push_back(stage);
}
}
if (!is_compute && build_ok) {
//fragment stage
current_stage = RD::SHADER_STAGE_FRAGMENT;
StringBuilder builder;
_build_variant_code(builder, variant, p_data->version, stage_templates[STAGE_TYPE_FRAGMENT]);
current_source = builder.as_string();
RD::ShaderStageSPIRVData stage;
stage.spirv = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_FRAGMENT, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
if (stage.spirv.size() == 0) {
build_ok = false;
} else {
stage.shader_stage = RD::SHADER_STAGE_FRAGMENT;
stages.push_back(stage);
}
}
if (is_compute) {
//compute stage
current_stage = RD::SHADER_STAGE_COMPUTE;
StringBuilder builder;
_build_variant_code(builder, variant, p_data->version, stage_templates[STAGE_TYPE_COMPUTE]);
current_source = builder.as_string();
RD::ShaderStageSPIRVData stage;
stage.spirv = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_COMPUTE, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
if (stage.spirv.size() == 0) {
build_ok = false;
} else {
stage.shader_stage = RD::SHADER_STAGE_COMPUTE;
stages.push_back(stage);
}
}
if (!build_ok) {
MutexLock lock(variant_set_mutex); //properly print the errors
ERR_PRINT("Error compiling " + String(current_stage == RD::SHADER_STAGE_COMPUTE ? "Compute " : (current_stage == RD::SHADER_STAGE_VERTEX ? "Vertex" : "Fragment")) + " shader, variant #" + itos(variant) + " (" + variant_defines[variant].text.get_data() + ").");
ERR_PRINT(error);
#ifdef DEBUG_ENABLED
ERR_PRINT("code:\n" + current_source.get_with_code_lines());
#endif
return;
}
Vector<uint8_t> shader_data = RD::get_singleton()->shader_compile_binary_from_spirv(stages, name + ":" + itos(variant));
ERR_FAIL_COND(shader_data.is_empty());
{
MutexLock lock(variant_set_mutex);
p_data->version->variants[variant] = RD::get_singleton()->shader_create_from_bytecode(shader_data, p_data->version->variants[variant]);
p_data->version->variant_data[variant] = shader_data;
}
}
RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_version) {
Version *version = version_owner.get_or_null(p_version);
RS::ShaderNativeSourceCode source_code;
ERR_FAIL_NULL_V(version, source_code);
source_code.versions.resize(variant_defines.size());
for (int i = 0; i < source_code.versions.size(); i++) {
if (!is_compute) {
//vertex stage
StringBuilder builder;
_build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_VERTEX]);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "vertex";
stage.code = builder.as_string();
source_code.versions.write[i].stages.push_back(stage);
}
if (!is_compute) {
//fragment stage
StringBuilder builder;
_build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_FRAGMENT]);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "fragment";
stage.code = builder.as_string();
source_code.versions.write[i].stages.push_back(stage);
}
if (is_compute) {
//compute stage
StringBuilder builder;
_build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_COMPUTE]);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "compute";
stage.code = builder.as_string();
source_code.versions.write[i].stages.push_back(stage);
}
}
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 = 3;
String ShaderRD::_get_cache_file_path(Version *p_version, int p_group) {
const String &sha1 = _version_get_sha1(p_version);
const String &api_safe_name = String(RD::get_singleton()->get_device_api_name()).validate_filename().to_lower();
const String &path = shader_cache_dir.path_join(name).path_join(group_sha256[p_group]).path_join(sha1) + "." + api_safe_name + ".cache";
return path;
}
bool ShaderRD::_load_from_cache(Version *p_version, int p_group) {
const String &path = _get_cache_file_path(p_version, p_group);
Ref<FileAccess> f = FileAccess::open(path, FileAccess::READ);
if (f.is_null()) {
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)group_to_variant_map[p_group].size(), false); //should not happen but check
for (uint32_t i = 0; i < variant_count; i++) {
int variant_id = group_to_variant_map[p_group][i];
uint32_t variant_size = f->get_32();
ERR_FAIL_COND_V(variant_size == 0 && variants_enabled[variant_id], false);
if (!variants_enabled[variant_id]) {
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[variant_id] = variant_bytes;
}
for (uint32_t i = 0; i < variant_count; i++) {
int variant_id = group_to_variant_map[p_group][i];
if (!variants_enabled[variant_id]) {
MutexLock lock(variant_set_mutex);
p_version->variants[variant_id] = RID();
continue;
}
{
MutexLock lock(variant_set_mutex);
RID shader = RD::get_singleton()->shader_create_from_bytecode(p_version->variant_data[variant_id], p_version->variants[variant_id]);
if (shader.is_null()) {
for (uint32_t j = 0; j < i; j++) {
int variant_free_id = group_to_variant_map[p_group][j];
RD::get_singleton()->free(p_version->variants[variant_free_id]);
}
ERR_FAIL_COND_V(shader.is_null(), false);
}
p_version->variants[variant_id] = 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, int p_group) {
ERR_FAIL_COND(!shader_cache_dir_valid);
const String &path = _get_cache_file_path(p_version, p_group);
Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE);
ERR_FAIL_COND(f.is_null());
f->store_buffer((const uint8_t *)shader_file_header, 4);
f->store_32(cache_file_version); // File version.
uint32_t variant_count = group_to_variant_map[p_group].size();
f->store_32(variant_count); // Variant count.
for (uint32_t i = 0; i < variant_count; i++) {
int variant_id = group_to_variant_map[p_group][i];
f->store_32(p_version->variant_data[variant_id].size()); // Stage count.
f->store_buffer(p_version->variant_data[variant_id].ptr(), p_version->variant_data[variant_id].size());
}
}
void ShaderRD::_allocate_placeholders(Version *p_version, int p_group) {
ERR_FAIL_NULL(p_version->variants);
for (uint32_t i = 0; i < group_to_variant_map[p_group].size(); i++) {
int variant_id = group_to_variant_map[p_group][i];
RID shader = RD::get_singleton()->shader_create_placeholder();
{
MutexLock lock(variant_set_mutex);
p_version->variants[variant_id] = shader;
}
}
}
// Try to compile all variants for a given group.
// Will skip variants that are disabled.
void ShaderRD::_compile_version(Version *p_version, int p_group) {
if (!group_enabled[p_group]) {
return;
}
typedef Vector<uint8_t> ShaderStageData;
p_version->variant_data = memnew_arr(ShaderStageData, variant_defines.size());
p_version->dirty = false;
if (shader_cache_dir_valid) {
if (_load_from_cache(p_version, p_group)) {
return;
}
}
CompileData compile_data;
compile_data.version = p_version;
compile_data.group = p_group;
#if 1
WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &ShaderRD::_compile_variant, &compile_data, group_to_variant_map[p_group].size(), -1, true, SNAME("ShaderCompilation"));
WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
#else
for (uint32_t i = 0; i < group_to_variant_map[p_group].size(); i++) {
_compile_variant(i, &compile_data);
}
#endif
bool all_valid = true;
for (uint32_t i = 0; i < group_to_variant_map[p_group].size(); i++) {
int variant_id = group_to_variant_map[p_group][i];
if (!variants_enabled[variant_id]) {
continue; // Disabled.
}
if (p_version->variants[variant_id].is_null()) {
all_valid = false;
break;
}
}
if (!all_valid) {
// Clear versions if they exist.
for (int i = 0; i < variant_defines.size(); i++) {
if (!variants_enabled[i] || !group_enabled[variant_defines[i].group]) {
continue; // Disabled.
}
if (!p_version->variants[i].is_null()) {
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;
p_version->variant_data = nullptr;
return;
} else if (shader_cache_dir_valid) {
// Save shader cache.
_save_to_cache(p_version, p_group);
}
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 HashMap<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.get_or_null(p_version);
ERR_FAIL_NULL(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 (const KeyValue<String, String> &E : p_code) {
version->code_sections[StringName(E.key.to_upper())] = E.value.utf8();
}
version->custom_defines.clear();
for (int i = 0; i < p_custom_defines.size(); i++) {
version->custom_defines.push_back(p_custom_defines[i].utf8());
}
version->dirty = true;
if (version->initialize_needed) {
_initialize_version(version);
for (int i = 0; i < group_enabled.size(); i++) {
if (!group_enabled[i]) {
_allocate_placeholders(version, i);
continue;
}
_compile_version(version, i);
}
version->initialize_needed = false;
}
}
void ShaderRD::version_set_compute_code(RID p_version, const HashMap<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.get_or_null(p_version);
ERR_FAIL_NULL(version);
version->compute_globals = p_compute_globals.utf8();
version->uniforms = p_uniforms.utf8();
version->code_sections.clear();
for (const KeyValue<String, String> &E : p_code) {
version->code_sections[StringName(E.key.to_upper())] = E.value.utf8();
}
version->custom_defines.clear();
for (int i = 0; i < p_custom_defines.size(); i++) {
version->custom_defines.push_back(p_custom_defines[i].utf8());
}
version->dirty = true;
if (version->initialize_needed) {
_initialize_version(version);
for (int i = 0; i < group_enabled.size(); i++) {
if (!group_enabled[i]) {
_allocate_placeholders(version, i);
continue;
}
_compile_version(version, i);
}
version->initialize_needed = false;
}
}
bool ShaderRD::version_is_valid(RID p_version) {
Version *version = version_owner.get_or_null(p_version);
ERR_FAIL_NULL_V(version, false);
if (version->dirty) {
_initialize_version(version);
for (int i = 0; i < group_enabled.size(); i++) {
if (!group_enabled[i]) {
_allocate_placeholders(version, i);
continue;
}
_compile_version(version, i);
}
}
return version->valid;
}
bool ShaderRD::version_free(RID p_version) {
if (version_owner.owns(p_version)) {
Version *version = version_owner.get_or_null(p_version);
_clear_version(version);
version_owner.free(p_version);
} else {
return false;
}
return true;
}
void ShaderRD::set_variant_enabled(int p_variant, bool p_enabled) {
ERR_FAIL_COND(version_owner.get_rid_count() > 0); //versions exist
ERR_FAIL_INDEX(p_variant, variants_enabled.size());
variants_enabled.write[p_variant] = p_enabled;
}
bool ShaderRD::is_variant_enabled(int p_variant) const {
ERR_FAIL_INDEX_V(p_variant, variants_enabled.size(), false);
return variants_enabled[p_variant];
}
void ShaderRD::enable_group(int p_group) {
ERR_FAIL_INDEX(p_group, group_enabled.size());
if (group_enabled[p_group]) {
// Group already enabled, do nothing.
return;
}
group_enabled.write[p_group] = true;
// Compile all versions again to include the new group.
List<RID> all_versions;
version_owner.get_owned_list(&all_versions);
for (const RID &E : all_versions) {
Version *version = version_owner.get_or_null(E);
_compile_version(version, p_group);
}
}
bool ShaderRD::is_group_enabled(int p_group) const {
return group_enabled[p_group];
}
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;
if (RD::get_singleton()->get_device_vendor_name() == "NVIDIA") {
use_32_threads = true;
}
String base_compute_define_text;
if (use_32_threads) {
base_compute_define_text = "\n#define NATIVE_LOCAL_GROUP_SIZE 32\n#define NATIVE_LOCAL_SIZE_2D_X 8\n#define NATIVE_LOCAL_SIZE_2D_Y 4\n";
} else {
base_compute_define_text = "\n#define NATIVE_LOCAL_GROUP_SIZE 64\n#define NATIVE_LOCAL_SIZE_2D_X 8\n#define NATIVE_LOCAL_SIZE_2D_Y 8\n";
}
base_compute_defines = base_compute_define_text.ascii();
}
void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String &p_general_defines) {
ERR_FAIL_COND(variant_defines.size());
ERR_FAIL_COND(p_variant_defines.is_empty());
general_defines = p_general_defines.utf8();
// When initialized this way, there is just one group and its always enabled.
group_to_variant_map.insert(0, LocalVector<int>{});
group_enabled.push_back(true);
for (int i = 0; i < p_variant_defines.size(); i++) {
variant_defines.push_back(VariantDefine(0, p_variant_defines[i], true));
variants_enabled.push_back(true);
group_to_variant_map[0].push_back(i);
}
if (!shader_cache_dir.is_empty()) {
group_sha256.resize(1);
_initialize_cache();
}
}
void ShaderRD::_initialize_cache() {
for (const KeyValue<int, LocalVector<int>> &E : group_to_variant_map) {
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());
hash_build.append("[group_id]");
hash_build.append(itos(E.key));
for (uint32_t i = 0; i < E.value.size(); i++) {
hash_build.append("[variant_defines:" + itos(E.value[i]) + "]");
hash_build.append(variant_defines[E.value[i]].text.get_data());
}
group_sha256[E.key] = hash_build.as_string().sha256_text();
Ref<DirAccess> d = DirAccess::open(shader_cache_dir);
ERR_FAIL_COND(d.is_null());
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(group_sha256[E.key]) != OK) {
Error err = d->make_dir(group_sha256[E.key]);
ERR_FAIL_COND(err != OK);
}
shader_cache_dir_valid = true;
print_verbose("Shader '" + name + "' (group " + itos(E.key) + ") SHA256: " + group_sha256[E.key]);
}
}
// Same as above, but allows specifying shader compilation groups.
void ShaderRD::initialize(const Vector<VariantDefine> &p_variant_defines, const String &p_general_defines) {
ERR_FAIL_COND(variant_defines.size());
ERR_FAIL_COND(p_variant_defines.is_empty());
general_defines = p_general_defines.utf8();
int max_group_id = 0;
for (int i = 0; i < p_variant_defines.size(); i++) {
// Fill variant array.
variant_defines.push_back(p_variant_defines[i]);
variants_enabled.push_back(true);
// Map variant array index to group id, so we can iterate over groups later.
if (!group_to_variant_map.has(p_variant_defines[i].group)) {
group_to_variant_map.insert(p_variant_defines[i].group, LocalVector<int>{});
}
group_to_variant_map[p_variant_defines[i].group].push_back(i);
// Track max size.
if (p_variant_defines[i].group > max_group_id) {
max_group_id = p_variant_defines[i].group;
}
}
// Set all to groups to false, then enable those that should be default.
group_enabled.resize_zeroed(max_group_id + 1);
bool *enabled_ptr = group_enabled.ptrw();
for (int i = 0; i < p_variant_defines.size(); i++) {
if (p_variant_defines[i].default_enabled) {
enabled_ptr[p_variant_defines[i].group] = true;
}
}
if (!shader_cache_dir.is_empty()) {
group_sha256.resize(max_group_id + 1);
_initialize_cache();
}
}
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);
if (remaining.size()) {
ERR_PRINT(itos(remaining.size()) + " shaders of type " + name + " were never freed");
while (remaining.size()) {
version_free(remaining.front()->get());
remaining.pop_front();
}
}
}

View file

@ -0,0 +1,211 @@
/**************************************************************************/
/* shader_rd.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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_RD_H
#define SHADER_RD_H
#include "core/os/mutex.h"
#include "core/string/string_builder.h"
#include "core/templates/hash_map.h"
#include "core/templates/local_vector.h"
#include "core/templates/rb_map.h"
#include "core/templates/rid_owner.h"
#include "core/variant/variant.h"
#include "servers/rendering_server.h"
class ShaderRD {
public:
struct VariantDefine {
int group = 0;
CharString text;
bool default_enabled = true;
VariantDefine(){};
VariantDefine(int p_group, const String &p_text, bool p_default_enabled) {
group = p_group;
default_enabled = p_default_enabled;
text = p_text.utf8();
}
};
private:
//versions
CharString general_defines;
Vector<VariantDefine> variant_defines;
Vector<bool> variants_enabled;
HashMap<int, LocalVector<int>> group_to_variant_map;
Vector<bool> group_enabled;
struct Version {
CharString uniforms;
CharString vertex_globals;
CharString compute_globals;
CharString fragment_globals;
HashMap<StringName, CharString> code_sections;
Vector<CharString> custom_defines;
Vector<uint8_t> *variant_data = nullptr;
RID *variants = nullptr; // Same size as variant defines.
bool valid;
bool dirty;
bool initialize_needed;
};
Mutex variant_set_mutex;
struct CompileData {
Version *version;
int group = 0;
};
void _compile_variant(uint32_t p_variant, const CompileData *p_data);
void _initialize_version(Version *p_version);
void _clear_version(Version *p_version);
void _compile_version(Version *p_version, int p_group);
void _allocate_placeholders(Version *p_version, int p_group);
RID_Owner<Version> version_owner;
struct StageTemplate {
struct Chunk {
enum Type {
TYPE_VERSION_DEFINES,
TYPE_MATERIAL_UNIFORMS,
TYPE_VERTEX_GLOBALS,
TYPE_FRAGMENT_GLOBALS,
TYPE_COMPUTE_GLOBALS,
TYPE_CODE,
TYPE_TEXT
};
Type type;
StringName code;
CharString text;
};
LocalVector<Chunk> chunks;
};
bool is_compute = false;
String name;
CharString base_compute_defines;
String base_sha256;
LocalVector<String> group_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,
STAGE_TYPE_COMPUTE,
STAGE_TYPE_MAX,
};
StageTemplate stage_templates[STAGE_TYPE_MAX];
void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template);
void _add_stage(const char *p_code, StageType p_stage_type);
String _version_get_sha1(Version *p_version) const;
String _get_cache_file_path(Version *p_version, int p_group);
bool _load_from_cache(Version *p_version, int p_group);
void _save_to_cache(Version *p_version, int p_group);
void _initialize_cache();
protected:
ShaderRD();
void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name);
public:
RID version_create();
void version_set_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines);
void version_set_compute_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_compute_globals, const Vector<String> &p_custom_defines);
_FORCE_INLINE_ RID version_get_shader(RID p_version, int p_variant) {
ERR_FAIL_INDEX_V(p_variant, variant_defines.size(), RID());
ERR_FAIL_COND_V(!variants_enabled[p_variant], RID());
Version *version = version_owner.get_or_null(p_version);
ERR_FAIL_NULL_V(version, RID());
if (version->dirty) {
_initialize_version(version);
for (int i = 0; i < group_enabled.size(); i++) {
if (!group_enabled[i]) {
_allocate_placeholders(version, i);
continue;
}
_compile_version(version, i);
}
}
if (!version->valid) {
return RID();
}
return version->variants[p_variant];
}
bool version_is_valid(RID p_version);
bool version_free(RID p_version);
// Enable/disable variants for things that you know won't be used at engine initialization time .
void set_variant_enabled(int p_variant, bool p_enabled);
bool is_variant_enabled(int p_variant) const;
// Enable/disable groups for things that might be enabled at run time.
void enable_group(int p_group);
bool is_group_enabled(int p_group) 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 = "");
void initialize(const Vector<VariantDefine> &p_variant_defines, const String &p_general_defines = "");
virtual ~ShaderRD();
};
#endif // SHADER_RD_H

View file

@ -0,0 +1,22 @@
#!/usr/bin/env python
Import("env")
if "RD_GLSL" in env["BUILDERS"]:
# find all include files
gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
# find all shader code(all glsl files excluding our include files)
glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
# make sure we recompile shaders if include files change
env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#glsl_builders.py"])
# compile shaders
for glsl_file in glsl_files:
env.RD_GLSL(glsl_file)
SConscript("effects/SCsub")
SConscript("environment/SCsub")
SConscript("forward_clustered/SCsub")
SConscript("forward_mobile/SCsub")

View file

@ -0,0 +1,108 @@
#[vertex]
#version 450
#VERSION_DEFINES
layout(push_constant, std140) uniform Pos {
vec4 src_rect;
vec4 dst_rect;
vec2 eye_center;
float k1;
float k2;
float upscale;
float aspect_ratio;
uint layer;
uint pad1;
}
data;
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 = 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);
}
#[fragment]
#version 450
#VERSION_DEFINES
layout(push_constant, std140) uniform Pos {
vec4 src_rect;
vec4 dst_rect;
vec2 eye_center;
float k1;
float k2;
float upscale;
float aspect_ratio;
uint layer;
bool convert_to_srgb;
}
data;
layout(location = 0) in vec2 uv;
layout(location = 0) out vec4 color;
#ifdef USE_LAYER
layout(binding = 0) uniform sampler2DArray src_rt;
#else
layout(binding = 0) uniform sampler2D src_rt;
#endif
vec3 linear_to_srgb(vec3 color) {
// If going to srgb, clamp from 0 to 1.
color = clamp(color, vec3(0.0), vec3(1.0));
const vec3 a = vec3(0.055f);
return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
}
void main() {
#ifdef APPLY_LENS_DISTORTION
vec2 coords = uv * 2.0 - 1.0;
vec2 offset = coords - data.eye_center;
// take aspect ratio into account
offset.y /= data.aspect_ratio;
// distort
vec2 offset_sq = offset * offset;
float radius_sq = offset_sq.x + offset_sq.y;
float radius_s4 = radius_sq * radius_sq;
float distortion_scale = 1.0 + (data.k1 * radius_sq) + (data.k2 * radius_s4);
offset *= distortion_scale;
// reapply aspect ratio
offset.y *= data.aspect_ratio;
// add our eye center back in
coords = offset + data.eye_center;
coords /= data.upscale;
// and check our color
if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) {
color = vec4(0.0, 0.0, 0.0, 1.0);
} else {
// layer is always used here
coords = (coords + vec2(1.0)) / vec2(2.0);
color = texture(src_rt, vec3(coords, data.layer));
}
#elif defined(USE_LAYER)
color = texture(src_rt, vec3(uv, data.layer));
#else
color = texture(src_rt, uv);
#endif
if (data.convert_to_srgb) {
color.rgb = linear_to_srgb(color.rgb); // Regular linear -> SRGB conversion.
}
}

View file

@ -0,0 +1,744 @@
#[vertex]
#version 450
#VERSION_DEFINES
#ifdef USE_ATTRIBUTES
layout(location = 0) in vec2 vertex_attrib;
layout(location = 3) in vec4 color_attrib;
layout(location = 4) in vec2 uv_attrib;
#if defined(CUSTOM0_USED)
layout(location = 6) in vec4 custom0_attrib;
#endif
#if defined(CUSTOM1_USED)
layout(location = 7) in vec4 custom1_attrib;
#endif
layout(location = 10) in uvec4 bone_attrib;
layout(location = 11) in vec4 weight_attrib;
#endif
#include "canvas_uniforms_inc.glsl"
layout(location = 0) out vec2 uv_interp;
layout(location = 1) out vec4 color_interp;
layout(location = 2) out vec2 vertex_interp;
#ifdef USE_NINEPATCH
layout(location = 3) out vec2 pixel_size_interp;
#endif
#ifdef MATERIAL_UNIFORMS_USED
layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
#MATERIAL_UNIFORMS
} material;
#endif
#GLOBALS
#ifdef USE_ATTRIBUTES
vec3 srgb_to_linear(vec3 color) {
return mix(pow((color.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), color.rgb * (1.0 / 12.92), lessThan(color.rgb, vec3(0.04045)));
}
#endif
void main() {
vec4 instance_custom = vec4(0.0);
#if defined(CUSTOM0_USED)
vec4 custom0 = vec4(0.0);
#endif
#if defined(CUSTOM1_USED)
vec4 custom1 = vec4(0.0);
#endif
#ifdef USE_PRIMITIVE
//weird bug,
//this works
vec2 vertex;
vec2 uv;
vec4 color;
if (gl_VertexIndex == 0) {
vertex = draw_data.points[0];
uv = draw_data.uvs[0];
color = vec4(unpackHalf2x16(draw_data.colors[0]), unpackHalf2x16(draw_data.colors[1]));
} else if (gl_VertexIndex == 1) {
vertex = draw_data.points[1];
uv = draw_data.uvs[1];
color = vec4(unpackHalf2x16(draw_data.colors[2]), unpackHalf2x16(draw_data.colors[3]));
} else {
vertex = draw_data.points[2];
uv = draw_data.uvs[2];
color = vec4(unpackHalf2x16(draw_data.colors[4]), unpackHalf2x16(draw_data.colors[5]));
}
uvec4 bones = uvec4(0, 0, 0, 0);
vec4 bone_weights = vec4(0.0);
#elif defined(USE_ATTRIBUTES)
vec2 vertex = vertex_attrib;
vec4 color = color_attrib;
if (bool(draw_data.flags & FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR)) {
color.rgb = srgb_to_linear(color.rgb);
}
color *= draw_data.modulation;
vec2 uv = uv_attrib;
#if defined(CUSTOM0_USED)
custom0 = custom0_attrib;
#endif
#if defined(CUSTOM1_USED)
custom1 = custom1_attrib;
#endif
uvec4 bones = bone_attrib;
vec4 bone_weights = weight_attrib;
#else // !USE_ATTRIBUTES
vec2 vertex_base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
vec2 vertex_base = vertex_base_arr[gl_VertexIndex];
vec2 uv = draw_data.src_rect.xy + abs(draw_data.src_rect.zw) * ((draw_data.flags & FLAGS_TRANSPOSE_RECT) != 0 ? vertex_base.yx : vertex_base.xy);
vec4 color = draw_data.modulation;
vec2 vertex = draw_data.dst_rect.xy + abs(draw_data.dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(draw_data.src_rect.zw, vec2(0.0, 0.0)));
uvec4 bones = uvec4(0, 0, 0, 0);
#endif // USE_ATTRIBUTES
mat4 model_matrix = mat4(vec4(draw_data.world_x, 0.0, 0.0), vec4(draw_data.world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(draw_data.world_ofs, 0.0, 1.0));
#define FLAGS_INSTANCING_MASK 0x7F
#define FLAGS_INSTANCING_HAS_COLORS (1 << 7)
#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 8)
uint instancing = draw_data.flags & FLAGS_INSTANCING_MASK;
#ifdef USE_ATTRIBUTES
if (instancing > 1) {
// trails
uint stride = 2 + 1 + 1; //particles always uses this format
uint trail_size = instancing;
uint offset = trail_size * stride * gl_InstanceIndex;
vec4 pcolor;
vec2 new_vertex;
{
uint boffset = offset + bone_attrib.x * stride;
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;
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;
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;
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 + 3];
vertex = new_vertex;
color *= pcolor;
} 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 (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
color *= transforms.data[offset];
offset += 1;
}
if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
instance_custom = transforms.data[offset];
}
matrix = transpose(matrix);
model_matrix = model_matrix * matrix;
}
}
#ifdef USE_POINT_SIZE
float point_size = 1.0;
#endif
#ifdef USE_WORLD_VERTEX_COORDS
vertex = (model_matrix * vec4(vertex, 0.0, 1.0)).xy;
#endif
{
#CODE : VERTEX
}
#ifdef USE_NINEPATCH
pixel_size_interp = abs(draw_data.dst_rect.zw) * vertex_base;
#endif
#if !defined(SKIP_TRANSFORM_USED) && !defined(USE_WORLD_VERTEX_COORDS)
vertex = (model_matrix * vec4(vertex, 0.0, 1.0)).xy;
#endif
color_interp = color;
if (canvas_data.use_pixel_snap) {
vertex = floor(vertex + 0.5);
// precision issue on some hardware creates artifacts within texture
// offset uv by a small amount to avoid
uv += 1e-5;
}
vertex = (canvas_data.canvas_transform * vec4(vertex, 0.0, 1.0)).xy;
vertex_interp = vertex;
uv_interp = uv;
gl_Position = canvas_data.screen_transform * vec4(vertex, 0.0, 1.0);
#ifdef USE_POINT_SIZE
gl_PointSize = point_size;
#endif
}
#[fragment]
#version 450
#VERSION_DEFINES
#include "canvas_uniforms_inc.glsl"
layout(location = 0) in vec2 uv_interp;
layout(location = 1) in vec4 color_interp;
layout(location = 2) in vec2 vertex_interp;
#ifdef USE_NINEPATCH
layout(location = 3) in vec2 pixel_size_interp;
#endif
layout(location = 0) out vec4 frag_color;
#ifdef MATERIAL_UNIFORMS_USED
layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
#MATERIAL_UNIFORMS
} material;
#endif
vec2 screen_uv_to_sdf(vec2 p_uv) {
return canvas_data.screen_to_sdf * 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, SAMPLER_LINEAR_CLAMP), uv).r;
d *= SDF_MAX_LENGTH;
return d * canvas_data.tex_to_sdf;
}
vec2 texture_sdf_normal(vec2 p_sdf) {
vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw;
const float EPSILON = 0.001;
return normalize(vec2(
texture(sampler2D(sdf_texture, SAMPLER_LINEAR_CLAMP), uv + vec2(EPSILON, 0.0)).r - texture(sampler2D(sdf_texture, SAMPLER_LINEAR_CLAMP), uv - vec2(EPSILON, 0.0)).r,
texture(sampler2D(sdf_texture, SAMPLER_LINEAR_CLAMP), uv + vec2(0.0, EPSILON)).r - texture(sampler2D(sdf_texture, SAMPLER_LINEAR_CLAMP), uv - vec2(0.0, EPSILON)).r));
}
vec2 sdf_to_screen_uv(vec2 p_sdf) {
return p_sdf * canvas_data.sdf_to_screen;
}
#GLOBALS
#ifdef LIGHT_CODE_USED
vec4 light_compute(
vec3 light_vertex,
vec3 light_position,
vec3 normal,
vec4 light_color,
float light_energy,
vec4 specular_shininess,
inout vec4 shadow_modulate,
vec2 screen_uv,
vec2 uv,
vec4 color, bool is_directional) {
vec4 light = vec4(0.0);
vec3 light_direction = vec3(0.0);
if (is_directional) {
light_direction = normalize(mix(vec3(light_position.xy, 0.0), vec3(0, 0, 1), light_position.z));
light_position = vec3(0.0);
} else {
light_direction = normalize(light_position - light_vertex);
}
#CODE : LIGHT
return light;
}
#endif
#ifdef USE_NINEPATCH
float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, int np_repeat, inout int draw_center) {
float tex_size = 1.0 / tex_pixel_size;
if (pixel < margin_begin) {
return pixel * tex_pixel_size;
} else if (pixel >= draw_size - margin_end) {
return (tex_size - (draw_size - pixel)) * tex_pixel_size;
} else {
if (!bool(draw_data.flags & FLAGS_NINEPACH_DRAW_CENTER)) {
draw_center--;
}
// np_repeat is passed as uniform using NinePatchRect::AxisStretchMode enum.
if (np_repeat == 0) { // Stretch.
// Convert to ratio.
float ratio = (pixel - margin_begin) / (draw_size - margin_begin - margin_end);
// Scale to source texture.
return (margin_begin + ratio * (tex_size - margin_begin - margin_end)) * tex_pixel_size;
} else if (np_repeat == 1) { // Tile.
// Convert to offset.
float ofs = mod((pixel - margin_begin), tex_size - margin_begin - margin_end);
// Scale to source texture.
return (margin_begin + ofs) * tex_pixel_size;
} else if (np_repeat == 2) { // Tile Fit.
// Calculate scale.
float src_area = draw_size - margin_begin - margin_end;
float dst_area = tex_size - margin_begin - margin_end;
float scale = max(1.0, floor(src_area / max(dst_area, 0.0000001) + 0.5));
// Convert to ratio.
float ratio = (pixel - margin_begin) / src_area;
ratio = mod(ratio * scale, 1.0);
// Scale to source texture.
return (margin_begin + ratio * dst_area) * tex_pixel_size;
} else { // Shouldn't happen, but silences compiler warning.
return 0.0;
}
}
}
#endif
#ifdef USE_LIGHTING
vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 light_color, vec4 specular_shininess, bool specular_shininess_used) {
float cNdotL = max(0.0, dot(normal, light_vec));
if (specular_shininess_used) {
//blinn
vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough
vec3 half_vec = normalize(view + light_vec);
float cNdotV = max(dot(normal, view), 0.0);
float cNdotH = max(dot(normal, half_vec), 0.0);
float cVdotH = max(dot(view, half_vec), 0.0);
float cLdotH = max(dot(light_vec, half_vec), 0.0);
float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25;
float blinn = pow(cNdotH, shininess);
blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75);
return specular_shininess.rgb * light_color * s + light_color * base_color * cNdotL;
} else {
return light_color * base_color * cNdotL;
}
}
//float distance = length(shadow_pos);
vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
#ifdef LIGHT_CODE_USED
,
vec3 shadow_modulate
#endif
) {
float shadow;
uint shadow_mode = light_array.data[light_base].flags & LIGHT_FLAGS_FILTER_MASK;
if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) {
shadow = textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
} else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) {
vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
shadow = 0.0;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
shadow /= 5.0;
} else { //PCF13
vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
shadow = 0.0;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 6.0, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 5.0, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 4.0, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 3.0, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 3.0, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 4.0, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 5.0, 0.0).x;
shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 6.0, 0.0).x;
shadow /= 13.0;
}
vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color);
#ifdef LIGHT_CODE_USED
shadow_color.rgb *= shadow_modulate;
#endif
shadow_color.a *= light_color.a; //respect light alpha
return mix(light_color, shadow_color, shadow);
}
void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) {
uint blend_mode = light_array.data[light_base].flags & LIGHT_FLAGS_BLEND_MASK;
switch (blend_mode) {
case LIGHT_FLAGS_BLEND_MODE_ADD: {
color.rgb += light_color.rgb * light_color.a;
} break;
case LIGHT_FLAGS_BLEND_MODE_SUB: {
color.rgb -= light_color.rgb * light_color.a;
} break;
case LIGHT_FLAGS_BLEND_MODE_MIX: {
color.rgb = mix(color.rgb, light_color.rgb, light_color.a);
} break;
}
}
#endif
float msdf_median(float r, float g, float b, float a) {
return min(max(min(r, g), min(max(r, g), b)), a);
}
void main() {
vec4 color = color_interp;
vec2 uv = uv_interp;
vec2 vertex = vertex_interp;
#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
#ifdef USE_NINEPATCH
int draw_center = 2;
uv = vec2(
map_ninepatch_axis(pixel_size_interp.x, abs(draw_data.dst_rect.z), draw_data.color_texture_pixel_size.x, draw_data.ninepatch_margins.x, draw_data.ninepatch_margins.z, int(draw_data.flags >> FLAGS_NINEPATCH_H_MODE_SHIFT) & 0x3, draw_center),
map_ninepatch_axis(pixel_size_interp.y, abs(draw_data.dst_rect.w), draw_data.color_texture_pixel_size.y, draw_data.ninepatch_margins.y, draw_data.ninepatch_margins.w, int(draw_data.flags >> FLAGS_NINEPATCH_V_MODE_SHIFT) & 0x3, draw_center));
if (draw_center == 0) {
color.a = 0.0;
}
uv = uv * draw_data.src_rect.zw + draw_data.src_rect.xy; //apply region if needed
#endif
if (bool(draw_data.flags & FLAGS_CLIP_RECT_UV)) {
uv = clamp(uv, draw_data.src_rect.xy, draw_data.src_rect.xy + abs(draw_data.src_rect.zw));
}
#endif
#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 if (bool(draw_data.flags & FLAGS_USE_LCD)) {
vec4 lcd_sample = texture(sampler2D(color_texture, texture_sampler), uv);
if (lcd_sample.a == 1.0) {
color.rgb = lcd_sample.rgb * color.a;
} else {
color = vec4(0.0, 0.0, 0.0, 0.0);
}
} 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;
vec3 normal;
#if defined(NORMAL_USED)
bool normal_used = true;
#else
bool normal_used = false;
#endif
if (normal_used || (using_light && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
normal.xy = texture(sampler2D(normal_texture, texture_sampler), uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
if (bool(draw_data.flags & FLAGS_TRANSPOSE_RECT)) {
normal.xy = normal.yx;
}
if (bool(draw_data.flags & FLAGS_FLIP_H)) {
normal.x = -normal.x;
}
if (bool(draw_data.flags & FLAGS_FLIP_V)) {
normal.y = -normal.y;
}
normal.z = sqrt(max(0.0, 1.0 - dot(normal.xy, normal.xy)));
normal_used = true;
} else {
normal = vec3(0.0, 0.0, 1.0);
}
vec4 specular_shininess;
#if defined(SPECULAR_SHININESS_USED)
bool specular_shininess_used = true;
#else
bool specular_shininess_used = false;
#endif
if (specular_shininess_used || (using_light && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
specular_shininess = texture(sampler2D(specular_texture, texture_sampler), uv);
specular_shininess *= unpackUnorm4x8(draw_data.specular_shininess);
specular_shininess_used = true;
} else {
specular_shininess = vec4(1.0);
}
#if defined(SCREEN_UV_USED)
vec2 screen_uv = gl_FragCoord.xy * canvas_data.screen_pixel_size;
#else
vec2 screen_uv = vec2(0.0);
#endif
vec3 light_vertex = vec3(vertex, 0.0);
vec2 shadow_vertex = vertex;
{
float normal_map_depth = 1.0;
#if defined(NORMAL_MAP_USED)
vec3 normal_map = vec3(0.0, 0.0, 1.0);
normal_used = true;
#endif
#CODE : FRAGMENT
#if defined(NORMAL_MAP_USED)
normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_map_depth);
#endif
}
if (normal_used) {
//convert by item transform
normal.xy = mat2(normalize(draw_data.world_x), normalize(draw_data.world_y)) * normal.xy;
//convert by canvas transform
normal = normalize((canvas_data.canvas_normal_transform * vec4(normal, 0.0)).xyz);
}
vec4 base_color = color;
#ifdef MODE_LIGHT_ONLY
float light_only_alpha = 0.0;
#elif !defined(MODE_UNSHADED)
color *= canvas_data.canvas_modulation;
#endif
#if defined(USE_LIGHTING) && !defined(MODE_UNSHADED)
// Directional Lights
for (uint i = 0; i < canvas_data.directional_light_count; i++) {
uint light_base = i;
vec2 direction = light_array.data[light_base].position;
vec4 light_color = light_array.data[light_base].color;
#ifdef LIGHT_CODE_USED
vec4 shadow_modulate = vec4(1.0);
light_color = light_compute(light_vertex, vec3(direction, light_array.data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, base_color, true);
#else
if (normal_used) {
vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_array.data[light_base].height));
light_color.rgb = light_normal_compute(light_vec, normal, base_color.rgb, light_color.rgb, specular_shininess, specular_shininess_used);
} else {
light_color.rgb *= base_color.rgb;
}
#endif
if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
vec4 shadow_uv = vec4(shadow_pos.x, light_array.data[light_base].shadow_y_ofs, shadow_pos.y * light_array.data[light_base].shadow_zfar_inv, 1.0);
light_color = light_shadow_compute(light_base, light_color, shadow_uv
#ifdef LIGHT_CODE_USED
,
shadow_modulate.rgb
#endif
);
}
light_blend_compute(light_base, light_color, color.rgb);
#ifdef MODE_LIGHT_ONLY
light_only_alpha += light_color.a;
#endif
}
// Positional Lights
for (uint i = 0; i < MAX_LIGHTS_PER_ITEM; i++) {
if (i >= light_count) {
break;
}
uint light_base = draw_data.lights[i >> 2];
light_base >>= (i & 3) * 8;
light_base &= 0xFF;
vec2 tex_uv = (vec4(vertex, 0.0, 1.0) * mat4(light_array.data[light_base].texture_matrix[0], light_array.data[light_base].texture_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
vec2 tex_uv_atlas = tex_uv * light_array.data[light_base].atlas_rect.zw + light_array.data[light_base].atlas_rect.xy;
if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) {
//if outside the light texture, light color is zero
continue;
}
vec4 light_color = textureLod(sampler2D(atlas_texture, texture_sampler), tex_uv_atlas, 0.0);
vec4 light_base_color = light_array.data[light_base].color;
#ifdef LIGHT_CODE_USED
vec4 shadow_modulate = vec4(1.0);
vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height);
light_color.rgb *= light_base_color.rgb;
light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, base_color, false);
#else
light_color.rgb *= light_base_color.rgb * light_base_color.a;
if (normal_used) {
vec3 light_pos = vec3(light_array.data[light_base].position, light_array.data[light_base].height);
vec3 pos = light_vertex;
vec3 light_vec = normalize(light_pos - pos);
light_color.rgb = light_normal_compute(light_vec, normal, base_color.rgb, light_color.rgb, specular_shininess, specular_shininess_used);
} else {
light_color.rgb *= base_color.rgb;
}
#endif
if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
vec2 pos_norm = normalize(shadow_pos);
vec2 pos_abs = abs(pos_norm);
vec2 pos_box = pos_norm / max(pos_abs.x, pos_abs.y);
vec2 pos_rot = pos_norm * mat2(vec2(0.7071067811865476, -0.7071067811865476), vec2(0.7071067811865476, 0.7071067811865476)); //is there a faster way to 45 degrees rot?
float tex_ofs;
float distance;
if (pos_rot.y > 0) {
if (pos_rot.x > 0) {
tex_ofs = pos_box.y * 0.125 + 0.125;
distance = shadow_pos.x;
} else {
tex_ofs = pos_box.x * -0.125 + (0.25 + 0.125);
distance = shadow_pos.y;
}
} else {
if (pos_rot.x < 0) {
tex_ofs = pos_box.y * -0.125 + (0.5 + 0.125);
distance = -shadow_pos.x;
} else {
tex_ofs = pos_box.x * 0.125 + (0.75 + 0.125);
distance = -shadow_pos.y;
}
}
distance *= light_array.data[light_base].shadow_zfar_inv;
//float distance = length(shadow_pos);
vec4 shadow_uv = vec4(tex_ofs, light_array.data[light_base].shadow_y_ofs, distance, 1.0);
light_color = light_shadow_compute(light_base, light_color, shadow_uv
#ifdef LIGHT_CODE_USED
,
shadow_modulate.rgb
#endif
);
}
light_blend_compute(light_base, light_color, color.rgb);
#ifdef MODE_LIGHT_ONLY
light_only_alpha += light_color.a;
#endif
}
#endif
#ifdef MODE_LIGHT_ONLY
color.a *= light_only_alpha;
#endif
frag_color = color;
}

View file

@ -0,0 +1,59 @@
#[vertex]
#version 450
#VERSION_DEFINES
layout(location = 0) in highp vec3 vertex;
layout(push_constant, std430) uniform Constants {
mat4 projection;
mat2x4 modelview;
vec2 direction;
float z_far;
float pad;
}
constants;
#ifdef MODE_SHADOW
layout(location = 0) out highp float depth;
#endif
void main() {
highp vec4 vtx = vec4(vertex, 1.0) * mat4(constants.modelview[0], constants.modelview[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
#ifdef MODE_SHADOW
depth = dot(constants.direction, vtx.xy);
#endif
gl_Position = constants.projection * vtx;
}
#[fragment]
#version 450
#VERSION_DEFINES
layout(push_constant, std430) uniform Constants {
mat4 projection;
mat2x4 modelview;
vec2 direction;
float z_far;
float pad;
}
constants;
#ifdef MODE_SHADOW
layout(location = 0) in highp float depth;
layout(location = 0) out highp float distance_buf;
#else
layout(location = 0) out highp float sdf_buf;
#endif
void main() {
#ifdef MODE_SHADOW
distance_buf = depth / constants.z_far;
#else
sdf_buf = 1.0;
#endif
}

View file

@ -0,0 +1,179 @@
#[compute]
#version 450
#VERSION_DEFINES
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_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;
layout(push_constant, std430) uniform Params {
ivec2 size;
int stride;
int shift;
ivec2 base_size;
uvec2 pad;
}
params;
#define SDF_MAX_LENGTH 16384.0
void main() {
ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
if (any(greaterThanEqual(pos, params.size))) { //too large, do nothing
return;
}
#ifdef MODE_LOAD
bool solid = imageLoad(src_pixels, pos).r > 0.5;
imageStore(dst_process, pos, solid ? ivec4(ivec2(-32767), 0, 0) : ivec4(ivec2(32767), 0, 0));
#endif
#ifdef MODE_LOAD_SHRINK
int s = 1 << params.shift;
ivec2 base = pos << params.shift;
ivec2 center = base + ivec2(params.shift);
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);
if (any(greaterThanEqual(src_pos, params.base_size))) {
continue;
}
bool solid = imageLoad(src_pixels, src_pos).r > 0.5;
if (solid) {
float dist = length(vec2(src_pos - center));
if (dist < d) {
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
#ifdef MODE_PROCESS
ivec2 base = pos << params.shift;
ivec2 center = base + ivec2(params.shift);
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;
const ivec2 ofs_table[ofs_table_size] = ivec2[](
ivec2(-1, -1),
ivec2(0, -1),
ivec2(+1, -1),
ivec2(-1, 0),
ivec2(+1, 0),
ivec2(-1, +1),
ivec2(0, +1),
ivec2(+1, +1));
float dist = length(vec2(rel - center));
for (int i = 0; i < ofs_table_size; i++) {
ivec2 src_pos = pos + ofs_table[i] * params.stride;
if (any(lessThan(src_pos, ivec2(0))) || any(greaterThanEqual(src_pos, params.size))) {
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;
rel = src_rel;
}
}
}
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 (solid) {
d = -d;
}
d /= SDF_MAX_LENGTH;
d = clamp(d, -1.0, 1.0);
imageStore(dst_sdf, pos, vec4(d));
#endif
#ifdef MODE_STORE_SHRINK
ivec2 base = pos << params.shift;
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 (solid) {
d = -d;
}
d /= SDF_MAX_LENGTH;
d = clamp(d, -1.0, 1.0);
imageStore(dst_sdf, pos, vec4(d));
#endif
}

View file

@ -0,0 +1,152 @@
#define MAX_LIGHTS_PER_ITEM 16
#define M_PI 3.14159265359
#define SDF_MAX_LENGTH 16384.0
//1 means enabled, 2+ means trails in use
#define FLAGS_INSTANCING_MASK 0x7F
#define FLAGS_INSTANCING_HAS_COLORS (1 << 7)
#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 8)
#define FLAGS_CLIP_RECT_UV (1 << 9)
#define FLAGS_TRANSPOSE_RECT (1 << 10)
#define FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR (1 << 11)
#define FLAGS_NINEPACH_DRAW_CENTER (1 << 12)
#define FLAGS_NINEPATCH_H_MODE_SHIFT 16
#define FLAGS_NINEPATCH_V_MODE_SHIFT 18
#define FLAGS_LIGHT_COUNT_SHIFT 20
#define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26)
#define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27)
#define FLAGS_USE_MSDF (1 << 28)
#define FLAGS_USE_LCD (1 << 29)
#define FLAGS_FLIP_H (1 << 30)
#define FLAGS_FLIP_V (1 << 31)
// Push Constant
layout(push_constant, std430) uniform DrawData {
vec2 world_x;
vec2 world_y;
vec2 world_ofs;
uint flags;
uint specular_shininess;
#ifdef USE_PRIMITIVE
vec2 points[3];
vec2 uvs[3];
uint colors[6];
#else
vec4 modulation;
vec4 ninepatch_margins;
vec4 dst_rect; //for built-in rect and UV
vec4 src_rect;
vec2 pad;
#endif
vec2 color_texture_pixel_size;
uint lights[4];
}
draw_data;
// In vulkan, sets should always be ordered using the following logic:
// Lower Sets: Sets that change format and layout less often
// Higher sets: Sets that change format and layout very often
// This is because changing a set for another with a different layout or format,
// invalidates all the upper ones (as likely internal base offset changes)
/* SET0: Globals */
// The values passed per draw primitives are cached within it
layout(set = 0, binding = 1, std140) uniform CanvasData {
mat4 canvas_transform;
mat4 screen_transform;
mat4 canvas_normal_transform;
vec4 canvas_modulation;
vec2 screen_pixel_size;
float time;
bool use_pixel_snap;
vec4 sdf_to_tex;
vec2 screen_to_sdf;
vec2 sdf_to_screen;
uint directional_light_count;
float tex_to_sdf;
uint pad1;
uint pad2;
}
canvas_data;
#define LIGHT_FLAGS_BLEND_MASK (3 << 16)
#define LIGHT_FLAGS_BLEND_MODE_ADD (0 << 16)
#define LIGHT_FLAGS_BLEND_MODE_SUB (1 << 16)
#define LIGHT_FLAGS_BLEND_MODE_MIX (2 << 16)
#define LIGHT_FLAGS_BLEND_MODE_MASK (3 << 16)
#define LIGHT_FLAGS_HAS_SHADOW (1 << 20)
#define LIGHT_FLAGS_FILTER_SHIFT 22
#define LIGHT_FLAGS_FILTER_MASK (3 << 22)
#define LIGHT_FLAGS_SHADOW_NEAREST (0 << 22)
#define LIGHT_FLAGS_SHADOW_PCF5 (1 << 22)
#define LIGHT_FLAGS_SHADOW_PCF13 (2 << 22)
struct Light {
mat2x4 texture_matrix; //light to texture coordinate matrix (transposed)
mat2x4 shadow_matrix; //light to shadow coordinate matrix (transposed)
vec4 color;
uint shadow_color; // packed
uint flags; //index to light texture
float shadow_pixel_size;
float height;
vec2 position;
float shadow_zfar_inv;
float shadow_y_ofs;
vec4 atlas_rect;
};
layout(set = 0, binding = 2, std140) uniform LightData {
Light data[MAX_LIGHTS];
}
light_array;
layout(set = 0, binding = 3) uniform texture2D atlas_texture;
layout(set = 0, binding = 4) uniform texture2D shadow_atlas_texture;
layout(set = 0, binding = 5) uniform sampler shadow_sampler;
layout(set = 0, binding = 6) uniform texture2D color_buffer;
layout(set = 0, binding = 7) uniform texture2D sdf_texture;
#include "samplers_inc.glsl"
layout(set = 0, binding = 9, std430) restrict readonly buffer GlobalShaderUniformData {
vec4 data[];
}
global_shader_uniforms;
/* SET1: Is reserved for the material */
//
/* SET2: Instancing and Skeleton */
layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms {
vec4 data[];
}
transforms;
/* SET3: Texture */
layout(set = 3, binding = 0) uniform texture2D color_texture;
layout(set = 3, binding = 1) uniform texture2D normal_texture;
layout(set = 3, binding = 2) uniform texture2D specular_texture;
layout(set = 3, binding = 3) uniform sampler texture_sampler;

View file

@ -0,0 +1,3 @@
#define CLUSTER_COUNTER_SHIFT 20
#define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1)
#define CLUSTER_COUNTER_MASK 0xfff

View file

@ -0,0 +1,115 @@
#[compute]
#version 450
#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
const vec3 usage_gradient[33] = vec3[]( // 1 (none) + 32
vec3(0.14, 0.17, 0.23),
vec3(0.24, 0.44, 0.83),
vec3(0.23, 0.57, 0.84),
vec3(0.22, 0.71, 0.84),
vec3(0.22, 0.85, 0.83),
vec3(0.21, 0.85, 0.72),
vec3(0.21, 0.85, 0.57),
vec3(0.20, 0.85, 0.42),
vec3(0.20, 0.85, 0.27),
vec3(0.27, 0.86, 0.19),
vec3(0.51, 0.85, 0.19),
vec3(0.57, 0.86, 0.19),
vec3(0.62, 0.85, 0.19),
vec3(0.67, 0.86, 0.20),
vec3(0.73, 0.85, 0.20),
vec3(0.78, 0.85, 0.20),
vec3(0.83, 0.85, 0.20),
vec3(0.85, 0.82, 0.20),
vec3(0.85, 0.76, 0.20),
vec3(0.85, 0.81, 0.20),
vec3(0.85, 0.65, 0.20),
vec3(0.84, 0.60, 0.21),
vec3(0.84, 0.56, 0.21),
vec3(0.84, 0.51, 0.21),
vec3(0.84, 0.46, 0.21),
vec3(0.84, 0.41, 0.21),
vec3(0.84, 0.36, 0.21),
vec3(0.84, 0.31, 0.21),
vec3(0.84, 0.27, 0.21),
vec3(0.83, 0.22, 0.22),
vec3(0.83, 0.22, 0.27),
vec3(0.83, 0.22, 0.32),
vec3(1.00, 0.63, 0.70));
layout(push_constant, std430) uniform Params {
uvec2 screen_size;
uvec2 cluster_screen_size;
uint cluster_shift;
uint cluster_type;
float z_near;
float z_far;
bool orthogonal;
uint max_cluster_element_count_div_32;
uint pad1;
uint pad2;
}
params;
layout(set = 0, binding = 1, std430) buffer restrict readonly ClusterData {
uint data[];
}
cluster_data;
layout(rgba16f, set = 0, binding = 2) uniform restrict writeonly image2D screen_buffer;
layout(set = 0, binding = 3) uniform texture2D depth_buffer;
layout(set = 0, binding = 4) uniform sampler depth_buffer_sampler;
void main() {
uvec2 screen_pos = gl_GlobalInvocationID.xy;
if (any(greaterThanEqual(screen_pos, params.screen_size))) {
return;
}
uvec2 cluster_pos = screen_pos >> params.cluster_shift;
uint offset = cluster_pos.y * params.cluster_screen_size.x + cluster_pos.x;
offset += params.cluster_screen_size.x * params.cluster_screen_size.y * params.cluster_type;
offset *= (params.max_cluster_element_count_div_32 + 32);
//depth buffers generally can't be accessed via image API
float depth = texelFetch(sampler2D(depth_buffer, depth_buffer_sampler), ivec2(screen_pos), 0).r * 2.0 - 1.0;
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));
}
depth /= params.z_far;
uint slice = uint(clamp(floor(depth * 32.0), 0.0, 31.0));
uint slice_minmax = cluster_data.data[offset + params.max_cluster_element_count_div_32 + slice];
uint item_min = slice_minmax & 0xFFFF;
uint item_max = slice_minmax >> 16;
uint item_count = 0;
for (uint i = 0; i < params.max_cluster_element_count_div_32; i++) {
uint slice_bits = cluster_data.data[offset + i];
while (slice_bits != 0) {
uint bit = findLSB(slice_bits);
uint item = i * 32 + bit;
if ((item >= item_min && item < item_max)) {
item_count++;
}
slice_bits &= ~(1 << bit);
}
}
item_count = min(item_count, 32);
vec3 color = usage_gradient[item_count];
color = mix(color * 1.2, color * 0.3, float(slice) / 31.0);
imageStore(screen_buffer, ivec2(screen_pos), vec4(color, 1.0));
}

View file

@ -0,0 +1,187 @@
#[vertex]
#version 450
#VERSION_DEFINES
layout(location = 0) in vec3 vertex_attrib;
layout(location = 0) out float depth_interp;
layout(location = 1) out flat uint element_index;
layout(push_constant, std430) uniform Params {
uint base_index;
uint pad0;
uint pad1;
uint pad2;
}
params;
layout(set = 0, binding = 1, std140) uniform State {
mat4 projection;
float inv_z_far;
uint screen_to_clusters_shift; // shift to obtain coordinates in block indices
uint cluster_screen_width; //
uint cluster_data_size; // how much data for a single cluster takes
uint cluster_depth_offset;
uint pad0;
uint pad1;
uint pad2;
}
state;
struct RenderElement {
uint type; //0-4
bool touches_near;
bool touches_far;
uint original_index;
mat3x4 transform_inv;
vec3 scale;
uint pad;
};
layout(set = 0, binding = 2, std430) buffer restrict readonly RenderElements {
RenderElement data[];
}
render_elements;
void main() {
element_index = params.base_index + gl_InstanceIndex;
vec3 vertex = vertex_attrib;
vertex *= render_elements.data[element_index].scale;
vertex = vec4(vertex, 1.0) * render_elements.data[element_index].transform_inv;
depth_interp = -vertex.z;
gl_Position = state.projection * vec4(vertex, 1.0);
}
#[fragment]
#version 450
#VERSION_DEFINES
#ifndef MOLTENVK_USED // Metal will corrupt GPU state otherwise
#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic) && defined(has_GL_KHR_shader_subgroup_vote)
#extension GL_KHR_shader_subgroup_ballot : enable
#extension GL_KHR_shader_subgroup_arithmetic : enable
#extension GL_KHR_shader_subgroup_vote : enable
#define USE_SUBGROUPS
#endif
#endif
layout(location = 0) in float depth_interp;
layout(location = 1) in flat uint element_index;
layout(set = 0, binding = 1, std140) uniform State {
mat4 projection;
float inv_z_far;
uint screen_to_clusters_shift; // shift to obtain coordinates in block indices
uint cluster_screen_width; //
uint cluster_data_size; // how much data for a single cluster takes
uint cluster_depth_offset;
uint pad0;
uint pad1;
uint pad2;
}
state;
//cluster data is layout linearly, each cell contains the follow information:
// - list of bits for every element to mark as used, so (max_elem_count/32)*4 uints
// - a uint for each element to mark the depth bits used when rendering (0-31)
layout(set = 0, binding = 3, std430) buffer restrict ClusterRender {
uint data[];
}
cluster_render;
#ifdef USE_ATTACHMENT
layout(location = 0) out vec4 frag_color;
#endif
void main() {
//convert from screen to cluster
uvec2 cluster = uvec2(gl_FragCoord.xy) >> state.screen_to_clusters_shift;
//get linear cluster offset from screen poss
uint cluster_offset = cluster.x + state.cluster_screen_width * cluster.y;
//multiply by data size to position at the beginning of the element list for this cluster
cluster_offset *= state.cluster_data_size;
//find the current element in the list and plot the bit to mark it as used
uint usage_write_offset = cluster_offset + (element_index >> 5);
uint usage_write_bit = 1 << (element_index & 0x1F);
uint aux = 0;
#ifdef USE_SUBGROUPS
uint cluster_thread_group_index;
if (!gl_HelperInvocation) {
//https://advances.realtimerendering.com/s2017/2017_Sig_Improved_Culling_final.pdf
uvec4 mask;
while (true) {
// find the cluster offset of the first active thread
// threads that did break; go inactive and no longer count
uint first = subgroupBroadcastFirst(cluster_offset);
// update the mask for thread that match this cluster
mask = subgroupBallot(first == cluster_offset);
if (first == cluster_offset) {
// This thread belongs to the group of threads that match this offset,
// so exit the loop.
break;
}
}
cluster_thread_group_index = subgroupBallotExclusiveBitCount(mask);
if (cluster_thread_group_index == 0) {
aux = atomicOr(cluster_render.data[usage_write_offset], usage_write_bit);
}
}
#else
// MoltenVK/Metal fails to compile shaders using gl_HelperInvocation for some GPUs
#ifndef MOLTENVK_USED
if (!gl_HelperInvocation)
#endif
{
aux = atomicOr(cluster_render.data[usage_write_offset], usage_write_bit);
}
#endif
//find the current element in the depth usage list and mark the current depth as used
float unit_depth = depth_interp * state.inv_z_far;
uint z_bit = clamp(uint(floor(unit_depth * 32.0)), 0, 31);
uint z_write_offset = cluster_offset + state.cluster_depth_offset + element_index;
uint z_write_bit = 1 << z_bit;
#ifdef USE_SUBGROUPS
if (!gl_HelperInvocation) {
z_write_bit = subgroupOr(z_write_bit); //merge all Zs
if (cluster_thread_group_index == 0) {
aux = atomicOr(cluster_render.data[z_write_offset], z_write_bit);
}
}
#else
// MoltenVK/Metal fails to compile shaders using gl_HelperInvocation for some GPUs
#ifndef MOLTENVK_USED
if (!gl_HelperInvocation)
#endif
{
aux = atomicOr(cluster_render.data[z_write_offset], z_write_bit);
}
#endif
#ifdef USE_ATTACHMENT
frag_color = vec4(float(aux));
#endif
}

View file

@ -0,0 +1,119 @@
#[compute]
#version 450
#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(push_constant, std430) uniform Params {
uint cluster_render_data_size; // how much data for a single cluster takes
uint max_render_element_count_div_32; //divided by 32
uvec2 cluster_screen_size;
uint render_element_count_div_32; //divided by 32
uint max_cluster_element_count_div_32; //divided by 32
uint pad1;
uint pad2;
}
params;
layout(set = 0, binding = 1, std430) buffer restrict readonly ClusterRender {
uint data[];
}
cluster_render;
layout(set = 0, binding = 2, std430) buffer restrict ClusterStore {
uint data[];
}
cluster_store;
struct RenderElement {
uint type; //0-4
bool touches_near;
bool touches_far;
uint original_index;
mat3x4 transform_inv;
vec3 scale;
uint pad;
};
layout(set = 0, binding = 3, std430) buffer restrict readonly RenderElements {
RenderElement data[];
}
render_elements;
void main() {
uvec2 pos = gl_GlobalInvocationID.xy;
if (any(greaterThanEqual(pos, params.cluster_screen_size))) {
return;
}
//counter for each type of render_element
//base offset for this cluster
uint base_offset = (pos.x + params.cluster_screen_size.x * pos.y);
uint src_offset = base_offset * params.cluster_render_data_size;
uint render_element_offset = 0;
//check all render_elements and see which one was written to
while (render_element_offset < params.render_element_count_div_32) {
uint bits = cluster_render.data[src_offset + render_element_offset];
while (bits != 0) {
//if bits exist, check the render_element
uint index_bit = findLSB(bits);
uint index = render_element_offset * 32 + index_bit;
uint type = render_elements.data[index].type;
uint z_range_offset = src_offset + params.max_render_element_count_div_32 + index;
uint z_range = cluster_render.data[z_range_offset];
//if object was written, z was written, but check just in case
if (z_range != 0) { //should always be > 0
uint from_z = findLSB(z_range);
uint to_z = findMSB(z_range) + 1;
if (render_elements.data[index].touches_near) {
from_z = 0;
}
if (render_elements.data[index].touches_far) {
to_z = 32;
}
// find cluster offset in the buffer used for indexing in the renderer
uint dst_offset = (base_offset + type * (params.cluster_screen_size.x * params.cluster_screen_size.y)) * (params.max_cluster_element_count_div_32 + 32);
uint orig_index = render_elements.data[index].original_index;
//store this index in the Z slices by setting the relevant bit
for (uint i = from_z; i < to_z; i++) {
uint slice_ofs = dst_offset + params.max_cluster_element_count_div_32 + i;
uint minmax = cluster_store.data[slice_ofs];
if (minmax == 0) {
minmax = 0xFFFF; //min 0, max 0xFFFF
}
uint elem_min = min(orig_index, minmax & 0xFFFF);
uint elem_max = max(orig_index + 1, minmax >> 16); //always store plus one, so zero means range is empty when not written to
minmax = elem_min | (elem_max << 16);
cluster_store.data[slice_ofs] = minmax;
}
uint store_word = orig_index >> 5;
uint store_bit = orig_index & 0x1F;
//store the actual render_element index at the end, so the rendering code can reference it
cluster_store.data[dst_offset + store_word] |= 1 << store_bit;
}
bits &= ~(1 << index_bit); //clear the bit to continue iterating
}
render_element_offset++;
}
}

View file

@ -0,0 +1,18 @@
struct DecalData {
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;
mediump float upper_fade;
mediump float lower_fade;
mediump mat3x4 normal_xform;
mediump vec3 normal;
mediump float normal_fade;
};

View file

@ -0,0 +1,19 @@
#!/usr/bin/env python
Import("env")
if "RD_GLSL" in env["BUILDERS"]:
# find all include files
gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")]
# find all shader code(all glsl files excluding our include files)
glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
# make sure we recompile shaders if include files change
env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#glsl_builders.py"])
# compile shaders
for glsl_file in glsl_files:
env.RD_GLSL(glsl_file)
SConscript("fsr2/SCsub")

Some files were not shown because too many files have changed in this diff Show more