summaryrefslogtreecommitdiff
path: root/servers/visual
diff options
context:
space:
mode:
Diffstat (limited to 'servers/visual')
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp9
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_rd.h7
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_storage_rd.h2
-rw-r--r--servers/visual/rasterizer_rd/shader_rd.cpp121
-rw-r--r--servers/visual/rasterizer_rd/shader_rd.h13
-rw-r--r--servers/visual/rasterizer_rd/shaders/SCsub1
-rw-r--r--servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl241
-rw-r--r--servers/visual/rendering_device.h20
8 files changed, 407 insertions, 7 deletions
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
index 7bb615eda9..888568e21a 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
@@ -1469,6 +1469,15 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
sky_ggx_samples_realtime = GLOBAL_GET("rendering/quality/reflections/ggx_samples_realtime");
sky_use_cubemap_array = GLOBAL_GET("rendering/quality/reflections/texture_array_reflections");
// sky_use_cubemap_array = false;
+
+ {
+ String defines = "";
+ Vector<String> versions;
+ versions.push_back("");
+ giprobe_lighting_shader.initialize(versions, defines);
+ giprobe_lighting_shader_version = giprobe_lighting_shader.version_create();
+ giprobe_lighting_shader_version_shader = giprobe_lighting_shader.version_get_shader(giprobe_lighting_shader_version, 0);
+ }
}
RasterizerSceneRD::~RasterizerSceneRD() {
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
index a1897cabe1..97e1d08d90 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
@@ -4,6 +4,7 @@
#include "core/rid_owner.h"
#include "servers/visual/rasterizer.h"
#include "servers/visual/rasterizer_rd/rasterizer_storage_rd.h"
+#include "servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl.gen.h"
#include "servers/visual/rendering_device.h"
class RasterizerSceneRD : public RasterizerScene {
@@ -108,6 +109,12 @@ private:
mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
+ /* GIPROBE INSTANCE */
+
+ GiprobeLightingShaderRD giprobe_lighting_shader;
+ RID giprobe_lighting_shader_version;
+ RID giprobe_lighting_shader_version_shader;
+
/* SHADOW ATLAS */
struct ShadowAtlas {
diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h
index 397e3c1b95..6cdc21c2f0 100644
--- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h
+++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h
@@ -778,6 +778,8 @@ public:
_FORCE_INLINE_ RID skeleton_get_3d_uniform_set(RID p_skeleton, RID p_shader, uint32_t p_set) const {
Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ ERR_FAIL_COND_V(!skeleton, RID());
+ ERR_FAIL_COND_V(skeleton->size == 0, RID());
if (skeleton->use_2d) {
return RID();
}
diff --git a/servers/visual/rasterizer_rd/shader_rd.cpp b/servers/visual/rasterizer_rd/shader_rd.cpp
index 58596f6a72..98e0c99c2e 100644
--- a/servers/visual/rasterizer_rd/shader_rd.cpp
+++ b/servers/visual/rasterizer_rd/shader_rd.cpp
@@ -33,11 +33,11 @@
#include "rasterizer_rd.h"
#include "servers/visual/rendering_device.h"
-void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name) {
+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;
//split vertex and shader code (thank you, shader compiler programmers from you know what company).
- {
+ if (p_vertex_code) {
String defines_tag = "\nVERSION_DEFINES";
String globals_tag = "\nVERTEX_SHADER_GLOBALS";
String material_tag = "\nMATERIAL_UNIFORMS";
@@ -79,7 +79,7 @@ void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, con
}
}
- {
+ if (p_fragment_code) {
String defines_tag = "\nVERSION_DEFINES";
String globals_tag = "\nFRAGMENT_SHADER_GLOBALS";
String material_tag = "\nMATERIAL_UNIFORMS";
@@ -135,6 +135,50 @@ void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, con
}
}
}
+
+ if (p_compute_code) {
+ is_compute = true;
+
+ String defines_tag = "\nVERSION_DEFINES";
+ String globals_tag = "\nCOMPUTE_SHADER_GLOBALS";
+ String material_tag = "\nMATERIAL_UNIFORMS";
+ String code_tag = "\nCOMPUTE_SHADER_CODE";
+ String code = p_compute_code;
+
+ int cpos = code.find(defines_tag);
+ if (cpos != -1) {
+ compute_codev = code.substr(0, cpos).ascii();
+ code = code.substr(cpos + defines_tag.length(), code.length());
+ }
+
+ cpos = code.find(material_tag);
+
+ if (cpos == -1) {
+ compute_code0 = code.ascii();
+ } else {
+ compute_code0 = code.substr(0, cpos).ascii();
+ code = code.substr(cpos + material_tag.length(), code.length());
+
+ cpos = code.find(globals_tag);
+
+ if (cpos == -1) {
+ compute_code1 = code.ascii();
+ } else {
+
+ compute_code1 = code.substr(0, cpos).ascii();
+ String code2 = code.substr(cpos + globals_tag.length(), code.length());
+
+ cpos = code2.find(code_tag);
+ if (cpos == -1) {
+ compute_code2 = code2.ascii();
+ } else {
+
+ compute_code2 = code2.substr(0, cpos).ascii();
+ compute_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii();
+ }
+ }
+ }
+ }
}
RID ShaderRD::version_create() {
@@ -171,7 +215,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
RD::ShaderStage current_stage = RD::SHADER_STAGE_VERTEX;
bool build_ok = true;
- {
+ if (!is_compute) {
//vertex stage
StringBuilder builder;
@@ -211,7 +255,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
}
}
- if (build_ok) {
+ if (!is_compute && build_ok) {
//fragment stage
current_stage = RD::SHADER_STAGE_FRAGMENT;
@@ -256,9 +300,50 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
}
}
+ if (is_compute) {
+ //compute stage
+ current_stage = RD::SHADER_STAGE_COMPUTE;
+
+ StringBuilder builder;
+
+ builder.append(compute_codev.get_data()); // version info (if exists)
+ builder.append("\n"); //make sure defines begin at newline
+ builder.append(general_defines.get_data());
+ builder.append(variant_defines[p_variant].get_data());
+
+ for (int j = 0; j < p_version->custom_defines.size(); j++) {
+ builder.append(p_version->custom_defines[j].get_data());
+ }
+
+ builder.append(compute_code0.get_data()); //first part of compute
+
+ builder.append(p_version->uniforms.get_data()); //uniforms (same for compute and fragment)
+
+ builder.append(compute_code1.get_data()); //second part of compute
+
+ builder.append(p_version->compute_globals.get_data()); // compute globals
+
+ builder.append(compute_code2.get_data()); //third part of compute
+
+ builder.append(p_version->compute_code.get_data()); // code
+
+ builder.append(compute_code3.get_data()); //fourth of compute
+
+ current_source = builder.as_string();
+ RD::ShaderStageData stage;
+ stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_COMPUTE, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
+ if (stage.spir_v.size() == 0) {
+ build_ok = false;
+ } else {
+
+ stage.shader_stage = RD::SHADER_STAGE_COMPUTE;
+ stages.push_back(stage);
+ }
+ }
+
if (!build_ok) {
variant_set_mutex.lock(); //properly print the errors
- ERR_PRINT("Error compiling " + String(current_stage == RD::SHADER_STAGE_VERTEX ? "Vertex" : "Fragment") + " shader, variant #" + itos(p_variant) + " (" + variant_defines[p_variant].get_data() + ").");
+ ERR_PRINT("Error compiling " + String(current_stage == RD::SHADER_STAGE_COMPUTE ? "Compute " : (current_stage == RD::SHADER_STAGE_VERTEX ? "Vertex" : "Fragment")) + " shader, variant #" + itos(p_variant) + " (" + variant_defines[p_variant].get_data() + ").");
ERR_PRINT(error);
#ifdef DEBUG_ENABLED
@@ -319,6 +404,8 @@ void ShaderRD::_compile_version(Version *p_version) {
void ShaderRD::version_set_code(RID p_version, const String &p_uniforms, const String &p_vertex_globals, const String &p_vertex_code, const String &p_fragment_globals, const String &p_fragment_light, const String &p_fragment_code, const Vector<String> &p_custom_defines) {
+ ERR_FAIL_COND(is_compute);
+
Version *version = version_owner.getornull(p_version);
ERR_FAIL_COND(!version);
version->vertex_globals = p_vertex_globals.utf8();
@@ -340,6 +427,28 @@ void ShaderRD::version_set_code(RID p_version, const String &p_uniforms, const S
}
}
+void ShaderRD::version_set_compute_code(RID p_version, const String &p_uniforms, const String &p_compute_globals, const String &p_compute_code, const Vector<String> &p_custom_defines) {
+
+ ERR_FAIL_COND(!is_compute);
+
+ Version *version = version_owner.getornull(p_version);
+ ERR_FAIL_COND(!version);
+ version->compute_globals = p_compute_globals.utf8();
+ version->compute_code = p_compute_code.utf8();
+ version->uniforms = p_uniforms.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) {
+ _compile_version(version);
+ version->initialize_needed = false;
+ }
+}
+
bool ShaderRD::version_is_valid(RID p_version) {
Version *version = version_owner.getornull(p_version);
ERR_FAIL_COND_V(!version, false);
diff --git a/servers/visual/rasterizer_rd/shader_rd.h b/servers/visual/rasterizer_rd/shader_rd.h
index 81169343d6..4d1e9576ce 100644
--- a/servers/visual/rasterizer_rd/shader_rd.h
+++ b/servers/visual/rasterizer_rd/shader_rd.h
@@ -55,6 +55,8 @@ class ShaderRD {
CharString uniforms;
CharString vertex_globals;
CharString vertex_code;
+ CharString compute_globals;
+ CharString compute_code;
CharString fragment_light;
CharString fragment_globals;
CharString fragment_code;
@@ -89,16 +91,25 @@ class ShaderRD {
CharString vertex_code2;
CharString vertex_code3;
+ bool is_compute = false;
+
+ CharString compute_codev; //for version and extensions
+ CharString compute_code0;
+ CharString compute_code1;
+ CharString compute_code2;
+ CharString compute_code3;
+
const char *name;
protected:
ShaderRD() {}
- void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name);
+ 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 String &p_uniforms, const String &p_vertex_globals, const String &p_vertex_code, const String &p_fragment_globals, const String &p_fragment_light, const String &p_fragment_code, const Vector<String> &p_custom_defines);
+ void version_set_compute_code(RID p_version, const String &p_uniforms, const String &p_compute_globals, const String &p_compute_code, 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());
diff --git a/servers/visual/rasterizer_rd/shaders/SCsub b/servers/visual/rasterizer_rd/shaders/SCsub
index b1fa9cd3f4..660523e29f 100644
--- a/servers/visual/rasterizer_rd/shaders/SCsub
+++ b/servers/visual/rasterizer_rd/shaders/SCsub
@@ -11,4 +11,5 @@ if 'RD_GLSL' in env['BUILDERS']:
env.RD_GLSL('sky.glsl');
env.RD_GLSL('tonemap.glsl');
env.RD_GLSL('copy.glsl');
+ env.RD_GLSL('giprobe_lighting.glsl');
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl b/servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl
new file mode 100644
index 0000000000..cec25f86f9
--- /dev/null
+++ b/servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl
@@ -0,0 +1,241 @@
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+
+#define NO_CHILDREN 0xFFFFFFFF
+#define GREY_VEC vec3(0.33333,0.33333,0.33333)
+
+struct CellPosition {
+ uint children[8];
+};
+
+
+layout(set=0,binding=1,std140) buffer CellPositions {
+ CellPosition data[];
+} cell_positions;
+
+struct CellMaterial {
+ uint position; // xyz 10 bits
+ uint albedo; //rgb albedo
+ uint emission; //rgb normalized with e as multiplier
+ uint normal; //RGB normal encoded
+};
+
+layout(set=0,binding=2,std140) buffer CellMaterials {
+ CellMaterial data[];
+} cell_materials;
+
+#define LIGHT_TYPE_DIRECTIONAL 0
+#define LIGHT_TYPE_OMNI 1
+#define LIGHT_TYPE_SPOT 2
+
+struct Light {
+
+ uint type;
+ float energy;
+ float radius;
+ float attenuation;
+
+ vec3 color;
+ float spot_angle_radians;
+
+ float advance;
+ float max_length;
+ uint pad0;
+ uint pad2;
+
+ vec3 position;
+ float spot_attenuation;
+
+
+ vec3 direction;
+ bool visible;
+
+ vec4 clip_planes[3];
+};
+
+layout(set=0,binding=3,std140) buffer Lights {
+ Light data[];
+} lights;
+
+
+layout(set=0,binding=4,std140) uniform Params {
+ vec3 limits;
+ float max_length;
+ uint size;
+ uint stack_size;
+ uint light_count;
+ float emission_scale;
+} params;
+
+
+layout (rgba8,set=0,binding=5) uniform restrict writeonly image3D color_tex;
+
+
+uint raymarch(float distance,float distance_adv,vec3 from,vec3 direction) {
+
+ uint result = NO_CHILDREN;
+
+ while (distance > -distance_adv) { //use this to avoid precision errors
+
+ uint cell = 0;
+
+ ivec3 pos = ivec3(from);
+ ivec3 ofs = ivec3(0);
+ ivec3 half_size = ivec3(params.size) / 2;
+ if (any(lessThan(pos,ivec3(0))) || any(greaterThanEqual(pos,ivec3(params.size)))) {
+ return NO_CHILDREN; //outside range
+ }
+
+ for (int i = 0; i < params.stack_size - 1; i++) {
+
+ bvec3 greater = greaterThanEqual(pos,ofs+half_size);
+
+ ofs += mix(ivec3(0),half_size,greater);
+
+ uint child = 0; //wonder if this can be done faster
+ if (greater.x) {
+ child|=1;
+ }
+ if (greater.y) {
+ child|=2;
+ }
+ if (greater.z) {
+ child|=4;
+ }
+
+ cell = cell_positions.data[cell].children[child];
+ if (cell == NO_CHILDREN)
+ break;
+
+ half_size >>= ivec3(1);
+ }
+
+ if ( cell != NO_CHILDREN) {
+ return cell; //found cell!
+ }
+
+ from += direction * distance_adv;
+ distance -= distance_adv;
+ }
+
+ return NO_CHILDREN;
+}
+
+bool compute_light_vector(uint light,uint cell, vec3 pos,out float attenuation, out vec3 light_pos) {
+
+ if (lights.data[light].type==LIGHT_TYPE_DIRECTIONAL) {
+
+ light_pos = pos - lights.data[light].direction * params.max_length;
+ attenuation = 1.0;
+
+ } else {
+
+ light_pos = lights.data[light].position;
+ float distance = length(pos - light_pos);
+ if (distance >= lights.data[light].radius) {
+ return false;
+ }
+
+ attenuation = pow( distance / lights.data[light].radius + 0.0001, lights.data[light].attenuation );
+
+
+ if (lights.data[light].type==LIGHT_TYPE_SPOT) {
+
+ vec3 rel = normalize(pos - light_pos);
+ float angle = acos(dot(rel,lights.data[light].direction));
+ if (angle > lights.data[light].spot_angle_radians) {
+ return false;
+ }
+
+ float d = clamp(angle / lights.data[light].spot_angle_radians, 0, 1);
+ attenuation *= pow(1.0 - d, lights.data[light].spot_attenuation);
+ }
+ }
+
+ return true;
+}
+
+void main() {
+
+ uint cell_index = gl_GlobalInvocationID.x;
+
+ uvec3 posu = uvec3(cell_materials.data[cell_index].position&0x3FF,(cell_materials.data[cell_index].position>>10)&0x3FF,cell_materials.data[cell_index].position>>20);
+ vec3 pos = vec3(posu);
+
+ vec3 emission = vec3(ivec3(cell_materials.data[cell_index].emission&0x3FF,(cell_materials.data[cell_index].emission>>10)&0x7FF,cell_materials.data[cell_index].emission>>21)) * params.emission_scale;
+ vec4 albedo = unpackUnorm4x8(cell_materials.data[cell_index].albedo);
+ vec4 normal = unpackSnorm4x8(cell_materials.data[cell_index].normal); //w >0.5 means, all directions
+
+#ifdef MODE_ANISOTROPIC
+ vec3 accum[6]=vec3[](vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0));
+ const vec3 accum_dirs[6]=vec3[](vec3(1.0,0.0,0.0),vec3(-1.0,0.0,0.0),vec3(0.0,1.0,0.0),vec3(0.0,-1.0,0.0),vec3(0.0,0.0,1.0),vec3(0.0,0.0,-1.0));
+#else
+ vec3 accum = vec3(0);
+#endif
+
+ for(uint i=0;i<params.light_count;i++) {
+
+ float attenuation;
+ vec3 light_pos;
+
+ if (!compute_light_vector(i,cell_index,pos,attenuation,light_pos)) {
+ continue;
+ }
+
+ float distance_adv = lights.data[i].advance;
+
+ vec3 light_dir = pos - light_pos;
+ float distance = length(light_dir);
+
+ light_dir=normalize(light_dir);
+
+ distance += distance_adv - mod(distance, distance_adv); //make it reach the center of the box always
+
+ vec3 from = pos - light_dir * distance; //approximate
+
+ if (normal.w < 0.5 && dot(normal.xyz,light_dir)>=0) {
+ continue; //not facing the light
+ }
+
+ uint result = raymarch(distance,distance_adv,from,lights.data[i].direction);
+
+ if (result != cell_index) {
+ continue; //was occluded
+ }
+
+ vec3 light = lights.data[i].color * albedo.rgb * attenuation;
+
+#ifdef MODE_ANISOTROPIC
+ for(uint j=0;j<6;j++) {
+ accum[j]+=max(0.0,dot(accum_dir,-light_dir))*light+emission;
+ }
+#else
+ if (normal.w < 0.5) {
+ accum+=max(0.0,dot(normal.xyz,-light_dir))*light+emission;
+ } else {
+ //all directions
+ accum+=light+emission;
+ }
+#endif
+
+ }
+
+#ifdef MODE_ANISOTROPIC
+
+ vec3 accum_total = accum[0]+accum[1]+accum[2]+accum[3]+accum[4]+accum[5];
+ float accum_total_energy = max(dot(accum_total,GREY_VEC),0.00001);
+ vec3 iso_positive = vec3(dot(aniso[0],GREY_VEC),dot(aniso[2],GREY_VEC),dot(aniso[4],GREY_VEC))/vec3(accum_total_energy);
+ vec3 iso_negative = vec3(dot(aniso[1],GREY_VEC),dot(aniso[3],GREY_VEC),dot(aniso[5],GREY_VEC))/vec3(accum_total_energy);
+
+ //store in 3D textures, total color, and isotropic magnitudes
+#else
+ //store in 3D texture pos, accum
+ imageStore(color_tex,ivec3(posu),vec4(accum,albedo.a));
+#endif
+
+}
diff --git a/servers/visual/rendering_device.h b/servers/visual/rendering_device.h
index 859a9e798c..d0afb3f13b 100644
--- a/servers/visual/rendering_device.h
+++ b/servers/visual/rendering_device.h
@@ -882,6 +882,13 @@ public:
virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0) = 0;
virtual bool render_pipeline_is_valid(RID p_pipeline) = 0;
+ /**************************/
+ /**** COMPUTE PIPELINE ****/
+ /**************************/
+
+ virtual RID compute_pipeline_create(RID p_shader) = 0;
+ virtual bool compute_pipeline_is_valid(RID p_pipeline) = 0;
+
/****************/
/**** SCREEN ****/
/****************/
@@ -930,6 +937,19 @@ public:
virtual void draw_list_end() = 0;
+ /***********************/
+ /**** COMPUTE LISTS ****/
+ /***********************/
+
+ typedef int64_t ComputeListID;
+
+ virtual ComputeListID compute_list_begin() = 0;
+ virtual void compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline) = 0;
+ virtual void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) = 0;
+ virtual void compute_list_set_push_constant(ComputeListID p_list, void *p_data, uint32_t p_data_size) = 0;
+ virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) = 0;
+ virtual void compute_list_end() = 0;
+
/***************/
/**** FREE! ****/
/***************/