Browse Source

SkyShaders working

clayjohn 3 years ago
parent
commit
3bb8e6a9fe

+ 1 - 1
drivers/gles3/rasterizer_gles3.h

@@ -92,9 +92,9 @@ public:
 
 	static void make_current() {
 		_create_func = _create_current;
+		low_end = true;
 	}
 
-	virtual bool is_low_end() const { return true; }
 	uint64_t get_frame_number() const { return frame; }
 	double get_frame_delta_time() const { return delta; }
 

+ 133 - 23
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -238,37 +238,81 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
 	dirty_sky_list = nullptr;
 }
 
-void RasterizerSceneGLES3::_draw_sky(Sky *p_sky, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_custom_fov, float p_energy, const Basis &p_sky_orientation) {
-	ERR_FAIL_COND(!p_sky);
+void RasterizerSceneGLES3::_draw_sky(Environment *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform) {
+	GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+	ERR_FAIL_COND(!p_env);
 
-	glDepthMask(GL_TRUE);
-	glEnable(GL_DEPTH_TEST);
-	glDisable(GL_CULL_FACE);
-	glDisable(GL_BLEND);
+	Sky *sky = sky_owner.get_or_null(p_env->sky);
+	ERR_FAIL_COND(!sky);
+
+	GLES3::SkyMaterialData *material_data = nullptr;
+	RID sky_material;
+
+	RS::EnvironmentBG background = p_env->background;
+
+	if (sky) {
+		ERR_FAIL_COND(!sky);
+		sky_material = sky->material;
+
+		if (sky_material.is_valid()) {
+			material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+			if (!material_data || !material_data->shader_data->valid) {
+				material_data = nullptr;
+			}
+		}
+
+		if (!material_data) {
+			sky_material = sky_globals.default_material;
+			material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+		}
+	} else if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+		sky_material = sky_globals.fog_material;
+		material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+	}
+
+	ERR_FAIL_COND(!material_data);
+	material_data->bind_uniforms();
+
+	GLES3::SkyShaderData *shader_data = material_data->shader_data;
+
+	ERR_FAIL_COND(!shader_data);
+
+	glDepthMask(GL_FALSE);
 	glDepthFunc(GL_LEQUAL);
-	glColorMask(1, 1, 1, 1);
+	glDisable(GL_BLEND);
 
-	//state.sky_shader.version_bind_shader(sky_globals.default_shader, SkyShaderGLES3::MODE_BACKGROUND);
-	//glBindBufferBase(GL_UNIFORM_BUFFER, 0, state.canvas_instance_data_buffers[state.current_buffer]); // Canvas data updated here
-	//glBindBufferBase(GL_UNIFORM_BUFFER, 1, state.canvas_instance_data_buffers[state.current_buffer]); // Global data
-	//glBindBufferBase(GL_UNIFORM_BUFFER, 2, state.canvas_instance_data_buffers[state.current_buffer]); // Directional light data
-	//glBindBufferBase(GL_UNIFORM_BUFFER, 3, state.canvas_instance_data_buffers[state.current_buffer]); // Material uniforms
+	//glBindBufferBase(GL_UNIFORM_BUFFER, 2, p_sky.directional light data); // Directional light data
 
 	// Camera
 	CameraMatrix camera;
 
-	if (p_custom_fov) {
+	if (p_env->sky_custom_fov) {
 		float near_plane = p_projection.get_z_near();
 		float far_plane = p_projection.get_z_far();
 		float aspect = p_projection.get_aspect();
 
-		camera.set_perspective(p_custom_fov, aspect, near_plane, far_plane);
-
+		camera.set_perspective(p_env->sky_custom_fov, aspect, near_plane, far_plane);
 	} else {
 		camera = p_projection;
 	}
-
+	Basis sky_transform = p_env->sky_orientation;
+	sky_transform.invert();
+	sky_transform = p_transform.basis * sky_transform;
+
+	GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+	GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::ORIENTATION, sky_transform, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+	GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1], shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+	GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+	GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+	GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::EXPOSURE, p_env->exposure, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+	GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TONEMAPPER, p_env->tone_mapper, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+	GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::WHITE, p_env->white, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+	// Bind a vertex array or else OpenGL complains. We won't actually use it
+	glBindVertexArray(sky_globals.quad_array);
 	glDrawArrays(GL_TRIANGLES, 0, 3);
+
+	//glDepthMask(GL_FALSE); // Leave off for transparent pass
+	glDepthFunc(GL_LESS);
 }
 
 Ref<Image> RasterizerSceneGLES3::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) {
@@ -674,12 +718,14 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
 	Environment *env = environment_owner.get_or_null(p_environment);
 
 	bool fb_cleared = false;
-
-	glDepthFunc(GL_LEQUAL);
+	glEnable(GL_DEPTH_TEST);
+	glDepthFunc(GL_LESS);
+	glDepthMask(GL_TRUE);
 
 	/* Depth Prepass */
 
 	glBindFramebuffer(GL_FRAMEBUFFER, rb->framebuffer);
+	glViewport(0, 0, rb->width, rb->height);
 
 	if (!fb_cleared) {
 		glClearDepth(1.0f);
@@ -730,7 +776,7 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
 	}
 
 	if (draw_sky) {
-		//_draw_sky(sky, render_data.cam_projection, render_data.cam_transform, env->sky_custom_fov, env->bg_energy, env->sky_orientation);
+		_draw_sky(env, render_data.cam_projection, render_data.cam_transform);
 	}
 
 	if (p_render_buffers.is_valid()) {
@@ -1014,9 +1060,9 @@ RasterizerSceneGLES3::RasterizerSceneGLES3(RasterizerStorageGLES3 *p_storage) {
 		String global_defines;
 		global_defines += "#define MAX_GLOBAL_VARIABLES 256\n"; // TODO: this is arbitrary for now
 		global_defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(sky_globals.max_directional_lights) + "\n";
-		state.sky_shader.initialize(global_defines);
-		sky_globals.shader_default_version = state.sky_shader.version_create();
-		state.sky_shader.version_bind_shader(sky_globals.shader_default_version, SkyShaderGLES3::MODE_BACKGROUND);
+		GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.initialize(global_defines);
+		sky_globals.shader_default_version = GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_create();
+		GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_bind_shader(sky_globals.shader_default_version, SkyShaderGLES3::MODE_BACKGROUND);
 	}
 
 	{
@@ -1038,12 +1084,76 @@ void sky() {
 
 		material_storage->material_set_shader(sky_globals.default_material, sky_globals.default_shader);
 	}
+	{
+		sky_globals.fog_shader = material_storage->shader_allocate();
+		material_storage->shader_initialize(sky_globals.fog_shader);
+
+		material_storage->shader_set_code(sky_globals.fog_shader, R"(
+// Default clear color sky shader.
+
+shader_type sky;
+
+uniform vec4 clear_color;
+
+void sky() {
+	COLOR = clear_color.rgb;
+}
+)");
+		sky_globals.fog_material = material_storage->material_allocate();
+		material_storage->material_initialize(sky_globals.fog_material);
+
+		material_storage->material_set_shader(sky_globals.fog_material, sky_globals.fog_shader);
+	}
+	{
+		{
+			//quad buffers
+
+			glGenBuffers(1, &sky_globals.quad);
+			glBindBuffer(GL_ARRAY_BUFFER, sky_globals.quad);
+			{
+				const float qv[16] = {
+					-1,
+					-1,
+					0,
+					0,
+					-1,
+					1,
+					0,
+					1,
+					1,
+					1,
+					1,
+					1,
+					1,
+					-1,
+					1,
+					0,
+				};
+
+				glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, qv, GL_STATIC_DRAW);
+			}
+
+			glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+
+			glGenVertexArrays(1, &sky_globals.quad_array);
+			glBindVertexArray(sky_globals.quad_array);
+			glBindBuffer(GL_ARRAY_BUFFER, sky_globals.quad);
+			glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, nullptr);
+			glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+			glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8));
+			glEnableVertexAttribArray(RS::ARRAY_TEX_UV);
+			glBindVertexArray(0);
+			glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+		}
+	}
 }
 
 RasterizerSceneGLES3::~RasterizerSceneGLES3() {
-	state.sky_shader.version_free(sky_globals.shader_default_version);
+	GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_free(sky_globals.shader_default_version);
 	storage->free(sky_globals.default_material);
 	storage->free(sky_globals.default_shader);
+	storage->free(sky_globals.fog_material);
+	storage->free(sky_globals.fog_shader);
 }
 
 #endif // GLES3_ENABLED

+ 6 - 7
drivers/gles3/rasterizer_scene_gles3.h

@@ -97,6 +97,10 @@ private:
 		RID shader_default_version;
 		RID default_material;
 		RID default_shader;
+		RID fog_material;
+		RID fog_shader;
+		GLuint quad = 0;
+		GLuint quad_array = 0;
 		uint32_t max_directional_lights = 4;
 		uint32_t roughness_layers = 8;
 		uint32_t ggx_samples = 128;
@@ -319,7 +323,7 @@ protected:
 		Sky *dirty_list = nullptr;
 
 		//State to track when radiance cubemap needs updating
-		//SkyMaterialData *prev_material;
+		GLES3::SkyMaterialData *prev_material;
 		Vector3 prev_position = Vector3(0.0, 0.0, 0.0);
 		float prev_time = 0.0f;
 
@@ -335,17 +339,12 @@ protected:
 
 	void _invalidate_sky(Sky *p_sky);
 	void _update_dirty_skys();
-	void _draw_sky(Sky *p_sky, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_custom_fov, float p_energy, const Basis &p_sky_orientation);
+	void _draw_sky(Environment *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform);
 
 public:
 	RasterizerStorageGLES3 *storage;
 	RasterizerCanvasGLES3 *canvas;
 
-	// References to shaders are needed in public space so they can be accessed in RasterizerStorageGLES3
-	struct State {
-		SkyShaderGLES3 sky_shader;
-	} state;
-
 	GeometryInstance *geometry_instance_create(RID p_base) override;
 	void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override;
 	void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override;

+ 13 - 86
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -342,25 +342,13 @@ void RasterizerStorageGLES3::canvas_light_occluder_set_polylines(RID p_occluder,
 */
 
 RS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const {
-	return RS::INSTANCE_NONE;
-
-	/*
-	if (mesh_owner.owns(p_rid)) {
+	if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
 		return RS::INSTANCE_MESH;
-	} else if (light_owner.owns(p_rid)) {
-		return RS::INSTANCE_LIGHT;
-	} else if (multimesh_owner.owns(p_rid)) {
+	}
+	if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_rid)) {
 		return RS::INSTANCE_MULTIMESH;
-	} else if (immediate_owner.owns(p_rid)) {
-		return RS::INSTANCE_IMMEDIATE;
-	} else if (reflection_probe_owner.owns(p_rid)) {
-		return RS::INSTANCE_REFLECTION_PROBE;
-	} else if (lightmap_capture_data_owner.owns(p_rid)) {
-		return RS::INSTANCE_LIGHTMAP_CAPTURE;
-	} else {
-		return RS::INSTANCE_NONE;
 	}
-*/
+	return RS::INSTANCE_NONE;
 }
 
 bool RasterizerStorageGLES3::free(RID p_rid) {
@@ -379,80 +367,19 @@ bool RasterizerStorageGLES3::free(RID p_rid) {
 	} else if (GLES3::MaterialStorage::get_singleton()->owns_material(p_rid)) {
 		GLES3::MaterialStorage::get_singleton()->material_free(p_rid);
 		return true;
+	} else if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
+		GLES3::MeshStorage::get_singleton()->mesh_free(p_rid);
+		return true;
+	} else if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_rid)) {
+		GLES3::MeshStorage::get_singleton()->multimesh_free(p_rid);
+		return true;
+	} else if (GLES3::MeshStorage::get_singleton()->owns_mesh_instance(p_rid)) {
+		GLES3::MeshStorage::get_singleton()->mesh_instance_free(p_rid);
+		return true;
 	} else {
 		return false;
 	}
 	/*
-	} else if (skeleton_owner.owns(p_rid)) {
-		Skeleton *s = skeleton_owner.get_or_null(p_rid);
-
-		if (s->update_list.in_list()) {
-			skeleton_update_list.remove(&s->update_list);
-		}
-
-		for (Set<InstanceBaseDependency *>::Element *E = s->instances.front(); E; E = E->next()) {
-			E->get()->skeleton = RID();
-		}
-
-		skeleton_allocate(p_rid, 0, false);
-
-		if (s->tex_id) {
-			glDeleteTextures(1, &s->tex_id);
-		}
-
-		skeleton_owner.free(p_rid);
-		memdelete(s);
-
-		return true;
-	} else if (mesh_owner.owns(p_rid)) {
-		Mesh *mesh = mesh_owner.get_or_null(p_rid);
-
-		mesh->instance_remove_deps();
-		mesh_clear(p_rid);
-
-		while (mesh->multimeshes.first()) {
-			MultiMesh *multimesh = mesh->multimeshes.first()->self();
-			multimesh->mesh = RID();
-			multimesh->dirty_aabb = true;
-
-			mesh->multimeshes.remove(mesh->multimeshes.first());
-
-			if (!multimesh->update_list.in_list()) {
-				multimesh_update_list.add(&multimesh->update_list);
-			}
-		}
-
-		mesh_owner.free(p_rid);
-		memdelete(mesh);
-
-		return true;
-	} else if (multimesh_owner.owns(p_rid)) {
-		MultiMesh *multimesh = multimesh_owner.get_or_null(p_rid);
-		multimesh->instance_remove_deps();
-
-		if (multimesh->mesh.is_valid()) {
-			Mesh *mesh = mesh_owner.get_or_null(multimesh->mesh);
-			if (mesh) {
-				mesh->multimeshes.remove(&multimesh->mesh_list);
-			}
-		}
-
-		multimesh_allocate(p_rid, 0, RS::MULTIMESH_TRANSFORM_3D, RS::MULTIMESH_COLOR_NONE);
-
-		_update_dirty_multimeshes();
-
-		multimesh_owner.free(p_rid);
-		memdelete(multimesh);
-
-		return true;
-	} else if (immediate_owner.owns(p_rid)) {
-		Immediate *im = immediate_owner.get_or_null(p_rid);
-		im->instance_remove_deps();
-
-		immediate_owner.free(p_rid);
-		memdelete(im);
-
-		return true;
 	} else if (light_owner.owns(p_rid)) {
 		Light *light = light_owner.get_or_null(p_rid);
 		light->instance_remove_deps();

+ 9 - 9
drivers/gles3/shaders/canvas.glsl

@@ -20,6 +20,15 @@ layout(location = 4) in vec2 uv_attrib;
 layout(location = 10) in uvec4 bone_attrib;
 layout(location = 11) in vec4 weight_attrib;
 
+#endif
+
+// This needs to be outside clang-format so the ubo comment is in the right place
+#ifdef MATERIAL_UNIFORMS_USED
+layout(std140) uniform MaterialUniforms{ //ubo:4
+
+#MATERIAL_UNIFORMS
+
+};
 #endif
 /* clang-format on */
 #include "canvas_uniforms_inc.glsl"
@@ -38,15 +47,6 @@ out vec2 pixel_size_interp;
 
 #endif
 
-#ifdef MATERIAL_UNIFORMS_USED
-layout(std140) uniform MaterialUniforms{
-//ubo:4
-
-#MATERIAL_UNIFORMS
-
-};
-#endif
-
 #GLOBALS
 
 void main() {

+ 35 - 24
drivers/gles3/shaders/sky.glsl

@@ -26,9 +26,9 @@ out vec2 uv_interp;
 
 void main() {
 	// One big triangle to cover the whole screen
-	vec2 base_arr[3] = vec2[](vec2(-1.0, -2.0), vec2(-1.0, 2.0), vec2(2.0, 2.0));
+	vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
 	uv_interp = base_arr[gl_VertexID];
-	gl_Position = vec4(uv_interp, 1.0, 1.0);
+	gl_Position = vec4(uv_interp, 0.0, 1.0);
 }
 
 /* clang-format off */
@@ -50,6 +50,8 @@ precision mediump int;
 #endif
 #endif
 
+#include "tonemap_inc.glsl"
+
 in vec2 uv_interp;
 
 /* clang-format on */
@@ -63,12 +65,7 @@ uniform sampler2D half_res; //texunit:-2
 uniform sampler2D quarter_res; //texunit:-3
 #endif
 
-layout(std140) uniform CanvasData { //ubo:0
-	mat3 orientation;
-	vec4 projection;
-	vec4 position_multiplier;
-	float time;
-	float luminance_multiplier;
+layout(std140) uniform SceneData { //ubo:0
 	float pad1;
 	float pad2;
 };
@@ -88,15 +85,16 @@ layout(std140) uniform DirectionalLights { //ubo:2
 }
 directional_lights;
 
+/* clang-format off */
+
 #ifdef MATERIAL_UNIFORMS_USED
-layout(std140) uniform MaterialUniforms{
-//ubo:3
+layout(std140) uniform MaterialUniforms{ //ubo:3
 
 #MATERIAL_UNIFORMS
 
-} material;
+};
 #endif
-
+/* clang-format on */
 #GLOBALS
 
 #ifdef USE_CUBEMAP_PASS
@@ -117,6 +115,12 @@ layout(std140) uniform MaterialUniforms{
 #define AT_QUARTER_RES_PASS false
 #endif
 
+// mat4 is a waste of space, but we don't have an easy way to set a mat3 uniform for now
+uniform mat4 orientation;
+uniform vec4 projection;
+uniform vec3 position;
+uniform float time;
+
 layout(location = 0) out vec4 frag_color;
 
 void main() {
@@ -128,7 +132,7 @@ void main() {
 	cube_normal.z = -cube_normal.z;
 	cube_normal = normalize(cube_normal);
 
-	vec2 uv = uv_interp * 0.5 + 0.5;
+	vec2 uv = gl_FragCoord.xy; // uv_interp * 0.5 + 0.5;
 
 	vec2 panorama_coords = vec2(atan(cube_normal.x, cube_normal.z), acos(cube_normal.y));
 
@@ -148,17 +152,17 @@ void main() {
 	vec3 inverted_cube_normal = cube_normal;
 	inverted_cube_normal.z *= -1.0;
 #ifdef USES_HALF_RES_COLOR
-	half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal) * luminance_multiplier;
+	half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal);
 #endif
 #ifdef USES_QUARTER_RES_COLOR
-	quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal) * luminance_multiplier;
+	quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal);
 #endif
 #else
 #ifdef USES_HALF_RES_COLOR
-	half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * luminance_multiplier;
+	half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
 #endif
 #ifdef USES_QUARTER_RES_COLOR
-	quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * luminance_multiplier;
+	quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
 #endif
 #endif
 
@@ -168,12 +172,19 @@ void main() {
 
 	}
 
-	frag_color.rgb = color * position_multiplier.w / luminance_multiplier;
-	frag_color.a = alpha;
+	// Tonemap before writing as we are writing to an sRGB framebuffer
+	color *= exposure;
+	color = apply_tonemapping(color, white);
+	color = linear_to_srgb(color);
 
-	// Blending is disabled for Sky, so alpha doesn't blend
-	// alpha is used for subsurface scattering so make sure it doesn't get applied to Sky
-	if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) {
-		frag_color.a = 0.0;
-	}
+#ifdef USE_BCS
+	color = apply_bcs(color, bcs);
+#endif
+
+#ifdef USE_COLOR_CORRECTION
+	color = apply_color_correction(color, color_correction);
+#endif
+
+	frag_color.rgb = color;
+	frag_color.a = alpha;
 }

+ 117 - 0
drivers/gles3/shaders/tonemap_inc.glsl

@@ -0,0 +1,117 @@
+#ifdef USE_BCS
+uniform vec3 bcs;
+#endif
+
+#ifdef USE_COLOR_CORRECTION
+#ifdef USE_1D_LUT
+uniform sampler2D source_color_correction; //texunit:-1
+#else
+uniform sampler3D source_color_correction; //texunit:-1
+#endif
+#endif
+
+// These could be grouped into some form of SceneData UBO along with time, will have to test performance though
+uniform int tonemapper;
+uniform float exposure;
+uniform float white;
+
+vec3 apply_bcs(vec3 color, vec3 bcs) {
+	color = mix(vec3(0.0), color, bcs.x);
+	color = mix(vec3(0.5), color, bcs.y);
+	color = mix(vec3(dot(vec3(1.0), color) * 0.33333), color, bcs.z);
+
+	return color;
+}
+#ifdef USE_COLOR_CORRECTION
+#ifdef USE_1D_LUT
+vec3 apply_color_correction(vec3 color) {
+	color.r = texture(source_color_correction, vec2(color.r, 0.0f)).r;
+	color.g = texture(source_color_correction, vec2(color.g, 0.0f)).g;
+	color.b = texture(source_color_correction, vec2(color.b, 0.0f)).b;
+	return color;
+}
+#else
+vec3 apply_color_correction(vec3 color) {
+	return textureLod(source_color_correction, color, 0.0).rgb;
+}
+#endif
+#endif
+
+vec3 tonemap_filmic(vec3 color, float p_white) {
+	// exposure bias: input scale (color *= bias, white *= bias) to make the brightness consistent with other tonemappers
+	// also useful to scale the input to the range that the tonemapper is designed for (some require very high input values)
+	// has no effect on the curve's general shape or visual properties
+	const float exposure_bias = 2.0f;
+	const float A = 0.22f * exposure_bias * exposure_bias; // bias baked into constants for performance
+	const float B = 0.30f * exposure_bias;
+	const float C = 0.10f;
+	const float D = 0.20f;
+	const float E = 0.01f;
+	const float F = 0.30f;
+
+	vec3 color_tonemapped = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F;
+	float p_white_tonemapped = ((p_white * (A * p_white + C * B) + D * E) / (p_white * (A * p_white + B) + D * F)) - E / F;
+
+	return color_tonemapped / p_white_tonemapped;
+}
+
+// Adapted from https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
+// (MIT License).
+vec3 tonemap_aces(vec3 color, float p_white) {
+	const float exposure_bias = 1.8f;
+	const float A = 0.0245786f;
+	const float B = 0.000090537f;
+	const float C = 0.983729f;
+	const float D = 0.432951f;
+	const float E = 0.238081f;
+
+	// Exposure bias baked into transform to save shader instructions. Equivalent to `color *= exposure_bias`
+	const mat3 rgb_to_rrt = mat3(
+			vec3(0.59719f * exposure_bias, 0.35458f * exposure_bias, 0.04823f * exposure_bias),
+			vec3(0.07600f * exposure_bias, 0.90834f * exposure_bias, 0.01566f * exposure_bias),
+			vec3(0.02840f * exposure_bias, 0.13383f * exposure_bias, 0.83777f * exposure_bias));
+
+	const mat3 odt_to_rgb = mat3(
+			vec3(1.60475f, -0.53108f, -0.07367f),
+			vec3(-0.10208f, 1.10813f, -0.00605f),
+			vec3(-0.00327f, -0.07276f, 1.07602f));
+
+	color *= rgb_to_rrt;
+	vec3 color_tonemapped = (color * (color + A) - B) / (color * (C * color + D) + E);
+	color_tonemapped *= odt_to_rgb;
+
+	p_white *= exposure_bias;
+	float p_white_tonemapped = (p_white * (p_white + A) - B) / (p_white * (C * p_white + D) + E);
+
+	return color_tonemapped / p_white_tonemapped;
+}
+
+vec3 tonemap_reinhard(vec3 color, float p_white) {
+	return (p_white * color + color) / (color * p_white + p_white);
+}
+
+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)));
+}
+
+#define TONEMAPPER_LINEAR 0
+#define TONEMAPPER_REINHARD 1
+#define TONEMAPPER_FILMIC 2
+#define TONEMAPPER_ACES 3
+
+vec3 apply_tonemapping(vec3 color, float p_white) { // inputs are LINEAR, always outputs clamped [0;1] color
+	// Ensure color values passed to tonemappers are positive.
+	// They can be negative in the case of negative lights, which leads to undesired behavior.
+	if (tonemapper == TONEMAPPER_LINEAR) {
+		return color;
+	} else if (tonemapper == TONEMAPPER_REINHARD) {
+		return tonemap_reinhard(max(vec3(0.0f), color), p_white);
+	} else if (tonemapper == TONEMAPPER_FILMIC) {
+		return tonemap_filmic(max(vec3(0.0f), color), p_white);
+	} else { // TONEMAPPER_ACES
+		return tonemap_aces(max(vec3(0.0f), color), p_white);
+	}
+}

+ 230 - 9
drivers/gles3/storage/material_storage.cpp

@@ -1278,13 +1278,13 @@ MaterialStorage::MaterialStorage() {
 	shader_data_request_func[RS::SHADER_SPATIAL] = nullptr;
 	shader_data_request_func[RS::SHADER_CANVAS_ITEM] = _create_canvas_shader_func;
 	shader_data_request_func[RS::SHADER_PARTICLES] = nullptr;
-	shader_data_request_func[RS::SHADER_SKY] = nullptr;
+	shader_data_request_func[RS::SHADER_SKY] = _create_sky_shader_func;
 	shader_data_request_func[RS::SHADER_FOG] = nullptr;
 
 	material_data_request_func[RS::SHADER_SPATIAL] = nullptr;
 	material_data_request_func[RS::SHADER_CANVAS_ITEM] = _create_canvas_material_func;
 	material_data_request_func[RS::SHADER_PARTICLES] = nullptr;
-	material_data_request_func[RS::SHADER_SKY] = nullptr;
+	material_data_request_func[RS::SHADER_SKY] = _create_sky_material_func;
 	material_data_request_func[RS::SHADER_FOG] = nullptr;
 
 	static_assert(sizeof(GlobalVariables::Value) == 16);
@@ -1365,7 +1365,7 @@ MaterialStorage::MaterialStorage() {
 		actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
 		actions.render_mode_defines["light_only"] = "#define MODE_LIGHT_ONLY\n";
 
-		actions.base_texture_binding_index = 1;
+		actions.base_texture_binding_index = 0;
 		actions.base_uniform_string = "";
 		actions.global_buffer_array_variable = "";
 
@@ -1626,10 +1626,10 @@ ShaderCompiler::DefaultIdentifierActions actions;
 		actions.renames["COLOR"] = "color";
 		actions.renames["ALPHA"] = "alpha";
 		actions.renames["EYEDIR"] = "cube_normal";
-		actions.renames["POSITION"] = "params.position_multiplier.xyz";
+		actions.renames["POSITION"] = "position";
 		actions.renames["SKY_COORDS"] = "panorama_coords";
 		actions.renames["SCREEN_UV"] = "uv";
-		actions.renames["TIME"] = "params.time";
+		actions.renames["TIME"] = "time";
 		actions.renames["PI"] = _MKSTR(Math_PI);
 		actions.renames["TAU"] = _MKSTR(Math_TAU);
 		actions.renames["E"] = _MKSTR(Math_E);
@@ -1660,15 +1660,12 @@ ShaderCompiler::DefaultIdentifierActions actions;
 		actions.renames["AT_CUBEMAP_PASS"] = "AT_CUBEMAP_PASS";
 		actions.renames["AT_HALF_RES_PASS"] = "AT_HALF_RES_PASS";
 		actions.renames["AT_QUARTER_RES_PASS"] = "AT_QUARTER_RES_PASS";
-		actions.custom_samplers["RADIANCE"] = "material_samplers[3]";
 		actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n";
 		actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n";
 		actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n";
 
-		actions.sampler_array_name = "material_samplers";
 		actions.base_texture_binding_index = 1;
 		actions.texture_layout_set = 1;
-		actions.base_uniform_string = "material.";
 		actions.base_varying_index = 10;
 
 		actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
@@ -2739,7 +2736,8 @@ void MaterialStorage::material_update_dependency(RID p_material, RendererStorage
 	}
 }
 
-// Canvas Shader Data
+/* Canvas Shader Data */
+
 void CanvasShaderData::set_code(const String &p_code) {
 	// compile the shader
 
@@ -2982,4 +2980,227 @@ GLES3::MaterialData *GLES3::_create_canvas_material_func(ShaderData *p_shader) {
 	return material_data;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// SKY SHADER
+
+void SkyShaderData::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;
+	ShaderCompiler::IdentifierActions actions;
+	actions.entry_point_stages["sky"] = ShaderCompiler::STAGE_FRAGMENT;
+
+	uses_time = false;
+	uses_half_res = false;
+	uses_quarter_res = false;
+	uses_position = false;
+	uses_light = false;
+
+	actions.render_mode_flags["use_half_res_pass"] = &uses_half_res;
+	actions.render_mode_flags["use_quarter_res_pass"] = &uses_quarter_res;
+
+	actions.usage_flag_pointers["TIME"] = &uses_time;
+	actions.usage_flag_pointers["POSITION"] = &uses_position;
+	actions.usage_flag_pointers["LIGHT0_ENABLED"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT0_ENERGY"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT0_DIRECTION"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT0_COLOR"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT0_SIZE"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT1_ENABLED"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT1_ENERGY"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT1_DIRECTION"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT1_COLOR"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT1_SIZE"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT2_ENABLED"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT2_ENERGY"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT2_DIRECTION"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT2_COLOR"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT2_SIZE"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT3_ENABLED"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT3_ENERGY"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT3_DIRECTION"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT3_COLOR"] = &uses_light;
+	actions.usage_flag_pointers["LIGHT3_SIZE"] = &uses_light;
+
+	actions.uniforms = &uniforms;
+
+	Error err = MaterialStorage::get_singleton()->shaders.compiler_sky.compile(RS::SHADER_SKY, code, &actions, path, gen_code);
+	ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
+
+	if (version.is_null()) {
+		version = MaterialStorage::get_singleton()->shaders.sky_shader.version_create();
+	}
+
+#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]);
+	}
+	print_line("\n**uniforms:\n" + gen_code.uniforms);
+	//	print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
+	//	print_line("\n**vertex_code:\n" + gen_code.vertex);
+	print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
+	print_line("\n**fragment_code:\n" + gen_code.fragment);
+	print_line("\n**light_code:\n" + gen_code.light);
+#endif
+
+	Vector<StringName> texture_uniform_names;
+	for (int i = 0; i < gen_code.texture_uniforms.size(); i++) {
+		texture_uniform_names.push_back(gen_code.texture_uniforms[i].name);
+	}
+
+	MaterialStorage::get_singleton()->shaders.sky_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, texture_uniform_names);
+	ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.sky_shader.version_is_valid(version));
+
+	ubo_size = gen_code.uniform_total_size;
+	ubo_offsets = gen_code.uniform_offsets;
+	texture_uniforms = gen_code.texture_uniforms;
+
+	valid = true;
+}
+
+void SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+	if (!p_texture.is_valid()) {
+		if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
+			default_texture_params[p_name].erase(p_index);
+
+			if (default_texture_params[p_name].is_empty()) {
+				default_texture_params.erase(p_name);
+			}
+		}
+	} else {
+		if (!default_texture_params.has(p_name)) {
+			default_texture_params[p_name] = Map<int, RID>();
+		}
+		default_texture_params[p_name][p_index] = p_texture;
+	}
+}
+
+void SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+	Map<int, StringName> order;
+
+	for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+		if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+			continue;
+		}
+
+		if (E.value.texture_order >= 0) {
+			order[E.value.texture_order + 100000] = E.key;
+		} else {
+			order[E.value.order] = E.key;
+		}
+	}
+
+	for (const KeyValue<int, StringName> &E : order) {
+		PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
+		pi.name = E.value;
+		p_param_list->push_back(pi);
+	}
+}
+
+void SkyShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
+	for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+		if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+			continue;
+		}
+
+		RendererMaterialStorage::InstanceShaderParam p;
+		p.info = ShaderLanguage::uniform_to_property_info(E.value);
+		p.info.name = E.key; //supply name
+		p.index = E.value.instance_index;
+		p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
+		p_param_list->push_back(p);
+	}
+}
+
+bool SkyShaderData::is_param_texture(const StringName &p_param) const {
+	if (!uniforms.has(p_param)) {
+		return false;
+	}
+
+	return uniforms[p_param].texture_order >= 0;
+}
+
+bool SkyShaderData::is_animated() const {
+	return false;
+}
+
+bool SkyShaderData::casts_shadows() const {
+	return false;
+}
+
+Variant SkyShaderData::get_default_parameter(const StringName &p_parameter) const {
+	if (uniforms.has(p_parameter)) {
+		ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+		Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+		return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
+	}
+	return Variant();
+}
+
+RS::ShaderNativeSourceCode SkyShaderData::get_native_source_code() const {
+	return MaterialStorage::get_singleton()->shaders.sky_shader.version_get_native_source_code(version);
+}
+
+SkyShaderData::SkyShaderData() {
+	valid = false;
+}
+
+SkyShaderData::~SkyShaderData() {
+	if (version.is_valid()) {
+		MaterialStorage::get_singleton()->shaders.sky_shader.version_free(version);
+	}
+}
+
+GLES3::ShaderData *GLES3::_create_sky_shader_func() {
+	SkyShaderData *shader_data = memnew(SkyShaderData);
+	return shader_data;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Sky material
+
+void SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+	return update_parameters_internal(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);
+}
+
+SkyMaterialData::~SkyMaterialData() {
+}
+GLES3::MaterialData *GLES3::_create_sky_material_func(ShaderData *p_shader) {
+	SkyMaterialData *material_data = memnew(SkyMaterialData);
+	material_data->shader_data = static_cast<SkyShaderData *>(p_shader);
+	//update will happen later anyway so do nothing.
+	return material_data;
+}
+
+void SkyMaterialData::bind_uniforms() {
+	// Bind Material Uniforms
+	glBindBufferBase(GL_UNIFORM_BUFFER, 3, uniform_buffer);
+
+	RID *textures = texture_cache.ptrw();
+	ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_data->texture_uniforms.ptrw();
+	for (int ti = 0; ti < texture_cache.size(); ti++) {
+		Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
+		glActiveTexture(GL_TEXTURE0 + ti);
+		glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
+
+		// Set sampler state here as the same texture can be used in multiple places with different flags
+		// Need to convert sampler state from ShaderLanguage::Texture* to RS::CanvasItemTexture*
+		RS::CanvasItemTextureFilter filter = RS::CanvasItemTextureFilter((int(texture_uniforms[ti].filter) + 1) % RS::CANVAS_ITEM_TEXTURE_FILTER_MAX);
+		RS::CanvasItemTextureRepeat repeat = RS::CanvasItemTextureRepeat((int(texture_uniforms[ti].repeat) + 1) % RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
+		texture->gl_set_filter(filter);
+		texture->gl_set_repeat(repeat);
+	}
+}
+
 #endif // !GLES3_ENABLED

+ 49 - 0
drivers/gles3/storage/material_storage.h

@@ -200,6 +200,55 @@ struct CanvasMaterialData : public MaterialData {
 
 MaterialData *_create_canvas_material_func(ShaderData *p_shader);
 
+/* Sky Materials */
+
+struct SkyShaderData : public ShaderData {
+	bool valid;
+	RID version;
+
+	Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+	Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
+
+	Vector<uint32_t> ubo_offsets;
+	uint32_t ubo_size;
+
+	String path;
+	String code;
+	Map<StringName, Map<int, RID>> default_texture_params;
+
+	bool uses_time;
+	bool uses_position;
+	bool uses_half_res;
+	bool uses_quarter_res;
+	bool uses_light;
+
+	virtual void set_code(const String &p_Code);
+	virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
+	virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+	virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
+	virtual bool is_param_texture(const StringName &p_param) const;
+	virtual bool is_animated() const;
+	virtual bool casts_shadows() const;
+	virtual Variant get_default_parameter(const StringName &p_parameter) const;
+	virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+	SkyShaderData();
+	virtual ~SkyShaderData();
+};
+
+ShaderData *_create_sky_shader_func();
+
+struct SkyMaterialData : public MaterialData {
+	SkyShaderData *shader_data = nullptr;
+
+	virtual void set_render_priority(int p_priority) {}
+	virtual void set_next_pass(RID p_pass) {}
+	virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+	virtual void bind_uniforms();
+	virtual ~SkyMaterialData();
+};
+
+MaterialData *_create_sky_material_func(ShaderData *p_shader);
+
 /* Global variable structs */
 struct GlobalVariables {
 	enum {

+ 9 - 0
drivers/gles3/storage/mesh_storage.h

@@ -388,6 +388,9 @@ public:
 
 	/* MESH INSTANCE API */
 
+	MeshInstance *get_mesh_instance(RID p_rid) { return mesh_instance_owner.get_or_null(p_rid); };
+	bool owns_mesh_instance(RID p_rid) { return mesh_instance_owner.owns(p_rid); };
+
 	virtual RID mesh_instance_create(RID p_base) override;
 	virtual void mesh_instance_free(RID p_rid) override;
 	virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override;
@@ -431,6 +434,9 @@ public:
 
 	/* MULTIMESH API */
 
+	MultiMesh *get_multimesh(RID p_rid) { return multimesh_owner.get_or_null(p_rid); };
+	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;
@@ -483,6 +489,9 @@ public:
 
 	/* SKELETON API */
 
+	Skeleton *get_skeleton(RID p_rid) { return skeleton_owner.get_or_null(p_rid); };
+	bool owns_skeleton(RID p_rid) { return skeleton_owner.owns(p_rid); };
+
 	virtual RID skeleton_allocate() override;
 	virtual void skeleton_initialize(RID p_rid) override;
 	virtual void skeleton_free(RID p_rid) override;

+ 1 - 1
servers/rendering/dummy/rasterizer_dummy.h

@@ -95,9 +95,9 @@ public:
 
 	static void make_current() {
 		_create_func = _create_current;
+		low_end = true;
 	}
 
-	bool is_low_end() const override { return true; }
 	uint64_t get_frame_number() const override { return frame; }
 	double get_frame_delta_time() const override { return delta; }
 

+ 1 - 0
servers/rendering/renderer_compositor.cpp

@@ -35,6 +35,7 @@
 #include "core/string/print_string.h"
 
 RendererCompositor *(*RendererCompositor::_create_func)() = nullptr;
+bool RendererCompositor::low_end = false;
 
 RendererCompositor *RendererCompositor::create() {
 	return _create_func();

+ 2 - 1
servers/rendering/renderer_compositor.h

@@ -71,6 +71,7 @@ private:
 protected:
 	static RendererCompositor *(*_create_func)();
 	bool back_end = false;
+	static bool low_end;
 
 public:
 	static RendererCompositor *create();
@@ -97,7 +98,7 @@ public:
 	virtual uint64_t get_frame_number() const = 0;
 	virtual double get_frame_delta_time() const = 0;
 
-	_FORCE_INLINE_ virtual bool is_low_end() const { return back_end; };
+	static bool is_low_end() { return low_end; };
 	virtual bool is_xr_enabled() const;
 
 	RendererCompositor();

+ 1 - 0
servers/rendering/renderer_rd/renderer_compositor_rd.h

@@ -131,6 +131,7 @@ public:
 
 	static void make_current() {
 		_create_func = _create_current;
+		low_end = false;
 	}
 
 	static RendererCompositorRD *singleton;

+ 1 - 5
servers/rendering/rendering_server_default.cpp

@@ -321,11 +321,7 @@ void RenderingServerDefault::set_debug_generate_wireframes(bool p_generate) {
 }
 
 bool RenderingServerDefault::is_low_end() const {
-	// FIXME: Commented out when rebasing vulkan branch on master,
-	// causes a crash, it seems rasterizer is not initialized yet the
-	// first time it's called.
-	//return RSG::rasterizer->is_low_end();
-	return false;
+	return RendererCompositor::is_low_end();
 }
 
 void RenderingServerDefault::_thread_exit() {

+ 3 - 1
servers/rendering/rendering_server_default.h

@@ -113,7 +113,9 @@ public:
 	_changes_changed();
 
 #else
-	_FORCE_INLINE_ static void redraw_request() { changes++; }
+	_FORCE_INLINE_ static void redraw_request() {
+		changes++;
+	}
 #endif
 
 #define WRITE_ACTION redraw_request();

+ 9 - 5
servers/rendering/shader_compiler.cpp

@@ -48,8 +48,8 @@ static String _mktab(int p_level) {
 
 static String _typestr(SL::DataType p_type) {
 	String type = ShaderLanguage::get_datatype_name(p_type);
-	if (ShaderLanguage::is_sampler_type(p_type)) {
-		type = type.replace("sampler", "texture"); //we use textures instead of samplers
+	if (!RS::get_singleton()->is_low_end() && ShaderLanguage::is_sampler_type(p_type)) {
+		type = type.replace("sampler", "texture"); //we use textures instead of samplers in Vulkan GLSL
 	}
 	return type;
 }
@@ -538,7 +538,11 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
 					continue; // Instances are indexed directly, don't need index uniforms.
 				}
 				if (SL::is_sampler_type(uniform.type)) {
-					ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_binding) + ") uniform ";
+					// Texture layouts are different for OpenGL GLSL and Vulkan GLSL
+					if (!RS::get_singleton()->is_low_end()) {
+						ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_binding) + ") ";
+					}
+					ucode += "uniform ";
 				}
 
 				bool is_buffer_global = !SL::is_sampler_type(uniform.type) && uniform.scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL;
@@ -1125,8 +1129,8 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
 							code += ", ";
 						}
 						String node_code = _dump_node_code(onode->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
-						if (is_texture_func && i == 1) {
-							//need to map from texture to sampler in order to sample
+						if (!RS::get_singleton()->is_low_end() && is_texture_func && i == 1) {
+							//need to map from texture to sampler in order to sample when using Vulkan GLSL
 							StringName texture_uniform;
 							bool correct_texture_uniform = false;