Browse Source

Completed material/2D shader support (missing SCREEN_TEXTURE)

Juan Linietsky 6 years ago
parent
commit
8bbbb97336

+ 9 - 5
drivers/gles3/shader_compiler_gles3.cpp

@@ -354,8 +354,6 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
 			}
 
 			r_gen_code.texture_uniforms.resize(max_texture_uniforms);
-			r_gen_code.texture_hints.resize(max_texture_uniforms);
-			r_gen_code.texture_types.resize(max_texture_uniforms);
 
 			Vector<int> uniform_sizes;
 			Vector<int> uniform_alignments;
@@ -380,9 +378,15 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
 				if (SL::is_sampler_type(E->get().type)) {
 					r_gen_code.vertex_global += ucode;
 					r_gen_code.fragment_global += ucode;
-					r_gen_code.texture_uniforms.write[E->get().texture_order] = _mkid(E->key());
-					r_gen_code.texture_hints.write[E->get().texture_order] = E->get().hint;
-					r_gen_code.texture_types.write[E->get().texture_order] = E->get().type;
+
+					GeneratedCode::Texture texture;
+					texture.name = _mkid(E->key());
+					texture.hint = E->get().hint;
+					texture.type = E->get().type;
+					texture.filter = E->get().filter;
+					texture.repeat = E->get().repeat;
+
+					r_gen_code.texture_uniforms.write[E->get().texture_order] = texture;
 				} else {
 					if (!uses_uniforms) {
 

+ 9 - 3
drivers/gles3/shader_compiler_gles3.h

@@ -51,9 +51,15 @@ public:
 	struct GeneratedCode {
 
 		Vector<CharString> defines;
-		Vector<StringName> texture_uniforms;
-		Vector<ShaderLanguage::DataType> texture_types;
-		Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints;
+		struct Texture {
+			StringName name;
+			ShaderLanguage::DataType type;
+			ShaderLanguage::ShaderNode::Uniform::Hint hint;
+			ShaderLanguage::ShaderNode::Uniform::Filter filter;
+			ShaderLanguage::ShaderNode::Uniform::Repeat repeat;
+		};
+
+		Vector<Texture> texture_uniforms;
 
 		Vector<uint32_t> uniform_offsets;
 		uint32_t uniform_total_size;

+ 6 - 6
drivers/vulkan/rendering_device_vulkan.cpp

@@ -4119,13 +4119,13 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
 			} break;
 			case UNIFORM_TYPE_UNIFORM_BUFFER: {
 				ERR_FAIL_COND_V_MSG(uniform.ids.size() != 1, RID(),
-						"Uniform buffer (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided).");
+						"Uniform buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided).");
 
 				Buffer *buffer = uniform_buffer_owner.getornull(uniform.ids[0]);
-				ERR_FAIL_COND_V_MSG(!buffer, RID(), "Uniform buffer (binding: " + itos(uniform.binding) + ") is invalid.");
+				ERR_FAIL_COND_V_MSG(!buffer, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
 
 				ERR_FAIL_COND_V_MSG(buffer->size != (uint32_t)set_uniform.length, RID(),
-						"Uniform buffer (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ").");
+						"Uniform buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ").");
 
 				write.dstArrayElement = 0;
 				write.descriptorCount = 1;
@@ -4137,13 +4137,13 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
 			} break;
 			case UNIFORM_TYPE_STORAGE_BUFFER: {
 				ERR_FAIL_COND_V_MSG(uniform.ids.size() != 1, RID(),
-						"Storage buffer (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided).");
+						"Storage buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided).");
 
 				Buffer *buffer = storage_buffer_owner.getornull(uniform.ids[0]);
-				ERR_FAIL_COND_V_MSG(!buffer, RID(), "Storage buffer (binding: " + itos(uniform.binding) + ") is invalid.");
+				ERR_FAIL_COND_V_MSG(!buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
 
 				ERR_FAIL_COND_V_MSG(buffer->size != (uint32_t)set_uniform.length, RID(),
-						"Storage buffer (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ").");
+						"Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ").");
 
 				write.dstArrayElement = 0;
 				write.descriptorCount = 1;

+ 3 - 4
drivers/vulkan/vulkan_context.cpp

@@ -86,7 +86,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(VkDebugU
 
 	free(message);
 
-	abort();
+	//	abort();
 	// Don't bail out, but keep going.
 	return false;
 }
@@ -416,8 +416,7 @@ Error VulkanContext::_create_physical_device() {
 	// Query fine-grained feature support for this device.
 	//  If app has specific feature requirements it should check supported
 	//  features based on this query
-	VkPhysicalDeviceFeatures physDevFeatures;
-	vkGetPhysicalDeviceFeatures(gpu, &physDevFeatures);
+	vkGetPhysicalDeviceFeatures(gpu, &physical_device_features);
 
 #define GET_INSTANCE_PROC_ADDR(inst, entrypoint)                                            \
 	{                                                                                       \
@@ -456,7 +455,7 @@ Error VulkanContext::_create_device() {
 		.ppEnabledLayerNames = NULL,
 		.enabledExtensionCount = enabled_extension_count,
 		.ppEnabledExtensionNames = (const char *const *)extension_names,
-		.pEnabledFeatures = NULL, // If specific features are required, pass them in here
+		.pEnabledFeatures = &physical_device_features, // If specific features are required, pass them in here
 	};
 	if (separate_present_queue) {
 		queues[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;

+ 1 - 0
drivers/vulkan/vulkan_context.h

@@ -39,6 +39,7 @@ class VulkanContext {
 	int frame_index;
 	VkFence fences[FRAME_LAG];
 	VkPhysicalDeviceMemoryProperties memory_properties;
+	VkPhysicalDeviceFeatures physical_device_features;
 
 	typedef struct {
 		VkImage image;

+ 21 - 19
scene/2d/canvas_item.cpp

@@ -1179,17 +1179,17 @@ void CanvasItem::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0));
 	ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(1.0));
 	ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle);
-	ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate", "normal_map", "specular_map", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT), DEFVAL(TEXTURE_REPEAT_PARENT));
-	ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose", "normal_map", "specular_map", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT), DEFVAL(TEXTURE_REPEAT_PARENT));
-	ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "normal_map", "specular_map", "clip_uv", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(true), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT), DEFVAL(TEXTURE_REPEAT_PARENT));
+	ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate", "normal_map", "specular_map", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+	ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose", "normal_map", "specular_map", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+	ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "normal_map", "specular_map", "clip_uv", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(true), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
 	ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box);
-	ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width", "normal_map", "specular_map", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_primitive, DEFVAL(Variant()), DEFVAL(1.0), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT), DEFVAL(TEXTURE_REPEAT_PARENT));
-	ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture", "normal_map", "specular_map", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT), DEFVAL(TEXTURE_REPEAT_PARENT));
-	ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture", "normal_map", "specular_map", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_colored_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT), DEFVAL(TEXTURE_REPEAT_PARENT));
+	ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width", "normal_map", "specular_map", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_primitive, DEFVAL(Variant()), DEFVAL(1.0), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+	ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture", "normal_map", "specular_map", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+	ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture", "normal_map", "specular_map", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_colored_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
 	ClassDB::bind_method(D_METHOD("draw_string", "font", "position", "text", "modulate", "clip_w"), &CanvasItem::draw_string, DEFVAL(Color(1, 1, 1)), DEFVAL(-1));
 	ClassDB::bind_method(D_METHOD("draw_char", "font", "position", "char", "next", "modulate"), &CanvasItem::draw_char, DEFVAL(Color(1, 1, 1)));
-	ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map", "specular_map", "transform", "modulate", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1)), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT), DEFVAL(TEXTURE_REPEAT_PARENT));
-	ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture", "normal_map", "specular_map", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_multimesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT), DEFVAL(TEXTURE_REPEAT_PARENT));
+	ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map", "specular_map", "transform", "modulate", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1)), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+	ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture", "normal_map", "specular_map", "specular_shinness", "texture_filter", "texture_repeat"), &CanvasItem::draw_multimesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
 
 	ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform);
 	ClassDB::bind_method(D_METHOD("draw_set_transform_matrix", "xform"), &CanvasItem::draw_set_transform_matrix);
@@ -1239,8 +1239,8 @@ void CanvasItem::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
 
 	ADD_GROUP("Texture", "texture_");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Parent Node,Nearest,Linear,MipmapLinear,MipmapNearest"), "set_texture_filter", "get_texture_filter");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Parent Node,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "ParentNode,Nearest,Linear,MipmapNearest,MipmapLinear,MipmapNearestAniso,MipmapLinearAniso"), "set_texture_filter", "get_texture_filter");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "ParentNode,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
 
 	ADD_GROUP("Material", "");
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material");
@@ -1260,14 +1260,16 @@ void CanvasItem::_bind_methods() {
 	BIND_CONSTANT(NOTIFICATION_ENTER_CANVAS);
 	BIND_CONSTANT(NOTIFICATION_EXIT_CANVAS);
 
-	BIND_ENUM_CONSTANT(TEXTURE_FILTER_PARENT);
+	BIND_ENUM_CONSTANT(TEXTURE_FILTER_PARENT_NODE);
 	BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST);
 	BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR);
-	BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR_WITH_MIPMAPS);
 	BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS);
+	BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR_WITH_MIPMAPS);
+	BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC);
+	BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC);
 	BIND_ENUM_CONSTANT(TEXTURE_FILTER_MAX);
 
-	BIND_ENUM_CONSTANT(TEXTURE_REPEAT_PARENT);
+	BIND_ENUM_CONSTANT(TEXTURE_REPEAT_PARENT_NODE);
 	BIND_ENUM_CONSTANT(TEXTURE_REPEAT_DISABLED);
 	BIND_ENUM_CONSTANT(TEXTURE_REPEAT_ENABLED);
 	BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MIRROR);
@@ -1341,7 +1343,7 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
 		return;
 	}
 
-	if (texture_filter == TEXTURE_FILTER_PARENT) {
+	if (texture_filter == TEXTURE_FILTER_PARENT_NODE) {
 		CanvasItem *parent_item = get_parent_item();
 		if (parent_item) {
 			texture_filter_cache = parent_item->texture_filter_cache;
@@ -1364,7 +1366,7 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
 
 	if (p_propagate) {
 		for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) {
-			if (!E->get()->toplevel && E->get()->texture_filter == TEXTURE_FILTER_PARENT) {
+			if (!E->get()->toplevel && E->get()->texture_filter == TEXTURE_FILTER_PARENT_NODE) {
 				E->get()->_update_texture_filter_changed(true);
 			}
 		}
@@ -1390,7 +1392,7 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
 		return;
 	}
 
-	if (texture_repeat == TEXTURE_REPEAT_PARENT) {
+	if (texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
 		CanvasItem *parent_item = get_parent_item();
 		if (parent_item) {
 			texture_repeat_cache = parent_item->texture_repeat_cache;
@@ -1411,7 +1413,7 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
 	update();
 	if (p_propagate) {
 		for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) {
-			if (!E->get()->toplevel && E->get()->texture_repeat == TEXTURE_REPEAT_PARENT) {
+			if (!E->get()->toplevel && E->get()->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
 				E->get()->_update_texture_repeat_changed(true);
 			}
 		}
@@ -1451,8 +1453,8 @@ CanvasItem::CanvasItem() :
 	notify_local_transform = false;
 	notify_transform = false;
 	light_mask = 1;
-	texture_repeat = TEXTURE_REPEAT_PARENT;
-	texture_filter = TEXTURE_FILTER_PARENT;
+	texture_repeat = TEXTURE_REPEAT_PARENT_NODE;
+	texture_filter = TEXTURE_FILTER_PARENT_NODE;
 	texture_filter_cache = VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
 	texture_repeat_cache = VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
 

+ 13 - 11
scene/2d/canvas_item.h

@@ -167,16 +167,18 @@ class CanvasItem : public Node {
 
 public:
 	enum TextureFilter {
-		TEXTURE_FILTER_PARENT,
+		TEXTURE_FILTER_PARENT_NODE,
 		TEXTURE_FILTER_NEAREST,
 		TEXTURE_FILTER_LINEAR,
-		TEXTURE_FILTER_LINEAR_WITH_MIPMAPS,
 		TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS,
+		TEXTURE_FILTER_LINEAR_WITH_MIPMAPS,
+		TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC,
+		TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC,
 		TEXTURE_FILTER_MAX
 	};
 
 	enum TextureRepeat {
-		TEXTURE_REPEAT_PARENT,
+		TEXTURE_REPEAT_PARENT_NODE,
 		TEXTURE_REPEAT_DISABLED,
 		TEXTURE_REPEAT_ENABLED,
 		TEXTURE_REPEAT_MIRROR,
@@ -329,16 +331,16 @@ public:
 	void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
 	void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, float p_width = 1.0);
 	void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color);
-	void draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT);
-	void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT);
-	void draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), bool p_clip_uv = false, TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT);
+	void draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+	void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+	void draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), bool p_clip_uv = false, TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
 	void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect);
-	void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), float p_width = 1, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT);
-	void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT);
-	void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT);
+	void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), float p_width = 1, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+	void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+	void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
 
-	void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT);
-	void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT);
+	void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+	void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
 
 	void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1);
 	float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", const Color &p_modulate = Color(1, 1, 1));

+ 25 - 0
servers/visual/rasterizer/rasterizer.cpp

@@ -35,6 +35,31 @@
 
 Rasterizer *(*Rasterizer::_create_func)() = NULL;
 
+void RasterizerScene::InstanceDependency::instance_notify_changed(bool p_aabb, bool p_dependencies) {
+	for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
+		E->key()->dependency_changed(p_aabb, p_dependencies);
+	}
+}
+void RasterizerScene::InstanceDependency::instance_notify_deleted(RID p_deleted) {
+	for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
+		E->key()->dependency_deleted(p_deleted);
+	}
+	for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
+		E->key()->dependencies.erase(this);
+	}
+}
+
+RasterizerScene::InstanceDependency::~InstanceDependency() {
+#ifdef DEBUG_ENABLED
+	if (instances.size()) {
+		WARN_PRINT("Leaked instance dependency: Bug - did not call instance_notify_deleted when freeing.");
+		for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
+			E->key()->dependencies.erase(this);
+		}
+	}
+#endif
+}
+
 Rasterizer *Rasterizer::create() {
 
 	return _create_func();

+ 67 - 10
servers/visual/rasterizer/rasterizer.h

@@ -34,6 +34,7 @@
 #include "core/math/camera_matrix.h"
 #include "servers/visual_server.h"
 
+#include "core/pair.h"
 #include "core/self_list.h"
 
 class RasterizerScene {
@@ -85,6 +86,20 @@ public:
 	virtual VS::EnvironmentBG environment_get_background(RID p_env) = 0;
 	virtual int environment_get_canvas_max_layer(RID p_env) = 0;
 
+	struct InstanceBase;
+
+	struct InstanceDependency {
+
+		void instance_notify_changed(bool p_aabb, bool p_dependencies);
+		void instance_notify_deleted(RID p_deleted);
+
+		~InstanceDependency();
+
+	private:
+		friend class InstanceBase;
+		Map<InstanceBase *, uint32_t> instances;
+	};
+
 	struct InstanceBase {
 
 		VS::InstanceType base_type;
@@ -97,6 +112,7 @@ public:
 
 		int depth_layer;
 		uint32_t layer_mask;
+		uint32_t instance_version;
 
 		//RID sampled_light;
 
@@ -124,8 +140,48 @@ public:
 		RID lightmap;
 		Vector<Color> lightmap_capture_data; //in a array (12 values) to avoid wasting space if unused. Alpha is unused, but needed to send to shader
 
-		virtual void base_removed() = 0;
-		virtual void base_changed(bool p_aabb, bool p_materials) = 0;
+		virtual void dependency_deleted(RID p_dependency) = 0;
+		virtual void dependency_changed(bool p_aabb, bool p_dependencies) = 0;
+
+		Set<InstanceDependency *> dependencies;
+
+		void instance_increase_version() {
+			instance_version++;
+		}
+
+		void update_dependency(InstanceDependency *p_dependency) {
+			dependencies.insert(p_dependency);
+			p_dependency->instances[this] = instance_version;
+		}
+
+		void clean_up_dependencies() {
+			List<Pair<InstanceDependency *, Map<InstanceBase *, uint32_t>::Element *> > to_clean_up;
+			for (Set<InstanceDependency *>::Element *E = dependencies.front(); E; E = E->next()) {
+				InstanceDependency *dep = E->get();
+				Map<InstanceBase *, uint32_t>::Element *F = dep->instances.find(this);
+				ERR_CONTINUE(!F);
+				if (F->get() != instance_version) {
+					Pair<InstanceDependency *, Map<InstanceBase *, uint32_t>::Element *> p;
+					p.first = dep;
+					p.second = F;
+					to_clean_up.push_back(p);
+				}
+			}
+
+			while (to_clean_up.size()) {
+				to_clean_up.front()->get().first->instances.erase(to_clean_up.front()->get().second);
+				to_clean_up.pop_front();
+			}
+		}
+
+		void clear_dependencies() {
+			for (Set<InstanceDependency *>::Element *E = dependencies.front(); E; E = E->next()) {
+				InstanceDependency *dep = E->get();
+				dep->instances.erase(this);
+			}
+			dependencies.clear();
+		}
+
 		InstanceBase() :
 				dependency_item(this) {
 
@@ -135,10 +191,15 @@ public:
 			visible = true;
 			depth_layer = 0;
 			layer_mask = 1;
+			instance_version = 0;
 			baked_light = false;
 			redraw_if_visible = false;
 			lightmap_capture = NULL;
 		}
+
+		virtual ~InstanceBase() {
+			clear_dependencies();
+		}
 	};
 
 	virtual RID light_instance_create(RID p_light) = 0;
@@ -241,7 +302,6 @@ public:
 
 	virtual void material_set_render_priority(RID p_material, int priority) = 0;
 	virtual void material_set_shader(RID p_shader_material, RID p_shader) = 0;
-	virtual RID material_get_shader(RID p_shader_material) const = 0;
 
 	virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) = 0;
 	virtual Variant material_get_param(RID p_material, const StringName &p_param) const = 0;
@@ -251,8 +311,7 @@ public:
 	virtual bool material_is_animated(RID p_material) = 0;
 	virtual bool material_casts_shadows(RID p_material) = 0;
 
-	virtual void material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) = 0;
-	virtual void material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) = 0;
+	virtual void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) = 0;
 
 	/* MESH API */
 
@@ -413,11 +472,8 @@ public:
 	virtual float reflection_probe_get_origin_max_distance(RID p_probe) const = 0;
 	virtual bool reflection_probe_renders_shadows(RID p_probe) const = 0;
 
-	virtual void instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) = 0;
-	virtual void instance_remove_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) = 0;
-
-	virtual void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
-	virtual void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
+	virtual void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
+	virtual void skeleton_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
 
 	/* GI PROBE API */
 
@@ -578,6 +634,7 @@ public:
 	virtual String get_video_adapter_vendor() const = 0;
 
 	static RasterizerStorage *base_singleton;
+
 	RasterizerStorage();
 	virtual ~RasterizerStorage() {}
 };

+ 574 - 237
servers/visual/rasterizer/rasterizer_canvas_rd.cpp

@@ -1,5 +1,7 @@
 #include "rasterizer_canvas_rd.h"
 #include "core/math/math_funcs.h"
+#include "core/project_settings.h"
+
 void RasterizerCanvasRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) {
 
 	p_mat4[0] = p_transform.elements[0][0];
@@ -82,7 +84,7 @@ RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap,
 		RID texture = storage->texture_get_rd_texture(p_texture);
 		if (!texture.is_valid()) {
 			//use default white texture
-			texture = default_textures.white_texture;
+			texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
 		}
 		u.ids.push_back(texture);
 		uniform_set.push_back(u);
@@ -95,7 +97,7 @@ RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap,
 		RID texture = storage->texture_get_rd_texture(p_normalmap);
 		if (!texture.is_valid()) {
 			//use default normal texture
-			texture = default_textures.normal_texture;
+			texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL);
 		}
 		u.ids.push_back(texture);
 		uniform_set.push_back(u);
@@ -108,7 +110,7 @@ RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap,
 		RID texture = storage->texture_get_rd_texture(p_specular);
 		if (!texture.is_valid()) {
 			//use default white texture
-			texture = default_textures.white_texture;
+			texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
 		}
 		u.ids.push_back(texture);
 		uniform_set.push_back(u);
@@ -118,7 +120,7 @@ RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap,
 		RD::Uniform u;
 		u.type = RD::UNIFORM_TYPE_SAMPLER;
 		u.binding = 4;
-		RID sampler = default_samplers.samplers[p_filter][p_repeat];
+		RID sampler = storage->sampler_rd_get_default(p_filter, p_repeat);
 		ERR_FAIL_COND_V(sampler.is_null(), RID());
 		u.ids.push_back(sampler);
 		uniform_set.push_back(u);
@@ -128,7 +130,7 @@ RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap,
 		RD::Uniform u;
 		u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER;
 		u.binding = 5;
-		u.ids.push_back(default_textures.default_multimesh_tb);
+		u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER));
 		uniform_set.push_back(u);
 	}
 
@@ -488,7 +490,7 @@ Size2i RasterizerCanvasRD::_bind_texture_binding(TextureBindingID p_binding, RD:
 }
 
 ////////////////////
-void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights) {
+void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) {
 
 	//create an empty push constant
 
@@ -566,98 +568,19 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
 		base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT;
 	}
 
-	if (light_count) {
-
-		//validate and update lighs if they are being used
-		bool invalid_uniform = state_data->light_uniform_set.is_valid() && !RD::get_singleton()->uniform_set_is_valid(state_data->light_uniform_set);
+	{
 
-		if (state_data->light_uniform_set.is_null() || invalid_uniform || light_uniform_set_dirty) {
-			//recreate uniform set
-			if (state_data->light_uniform_set.is_valid() && !invalid_uniform) {
-				RD::get_singleton()->free(state_data->light_uniform_set);
-			}
+		RID &canvas_item_state = light_count ? state_data->state_uniform_set_with_light : state_data->state_uniform_set;
 
-			state_data->light_uniform_set = RID();
+		bool invalid_uniform = canvas_item_state.is_valid() && !RD::get_singleton()->uniform_set_is_valid(canvas_item_state);
 
+		if (canvas_item_state.is_null() || invalid_uniform || (light_count > 0 && light_uniform_set_dirty)) {
+			//re create canvas state
 			Vector<RD::Uniform> uniforms;
-			{
-				RD::Uniform u;
-				u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
-				u.binding = 0;
-				u.ids.push_back(state.lights_uniform_buffer);
-				uniforms.push_back(u);
-			}
-
-			{
-
-				RD::Uniform u_lights;
-				u_lights.type = RD::UNIFORM_TYPE_TEXTURE;
-				u_lights.binding = 1;
-
-				RD::Uniform u_shadows;
-				u_shadows.type = RD::UNIFORM_TYPE_TEXTURE;
-				u_shadows.binding = 2;
-
-				//lights
-				for (uint32_t i = 0; i < state.max_lights_per_item; i++) {
-					if (i < light_count) {
-
-						CanvasLight *cl = canvas_light_owner.getornull(light_cache[i]->light_internal);
-						ERR_CONTINUE(!cl);
-
-						RID rd_texture;
-
-						if (cl->texture.is_valid()) {
-							rd_texture = storage->texture_get_rd_texture(cl->texture);
-						}
-						if (rd_texture.is_valid()) {
-							u_lights.ids.push_back(rd_texture);
-						} else {
-							u_lights.ids.push_back(default_textures.white_texture);
-						}
-						if (cl->shadow.texture.is_valid()) {
-							u_shadows.ids.push_back(cl->shadow.texture);
-						} else {
-							u_shadows.ids.push_back(default_textures.black_texture);
-						}
-					} else {
-						u_lights.ids.push_back(default_textures.white_texture);
-						u_shadows.ids.push_back(default_textures.black_texture);
-					}
-				}
-
-				uniforms.push_back(u_lights);
-				uniforms.push_back(u_shadows);
-			}
 
-			{
-				RD::Uniform u;
-				u.type = RD::UNIFORM_TYPE_SAMPLER;
-				u.binding = 3;
-				u.ids.push_back(state.shadow_sampler);
-				uniforms.push_back(u);
-			}
-
-			state_data->light_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader_light, 3);
-		}
-
-		RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, state_data->light_uniform_set, 3);
-		light_mode = PIPELINE_LIGHT_MODE_ENABLED;
-	} else {
-		light_mode = PIPELINE_LIGHT_MODE_DISABLED;
-	}
-
-	{
-		//state uniform
-		bool invalid_uniform = state_data->state_uniform_set.is_valid() && !RD::get_singleton()->uniform_set_is_valid(state_data->state_uniform_set);
-
-		if (state_data->state_uniform_set.is_null() || invalid_uniform) {
-			if (state_data->state_uniform_set.is_valid() && !invalid_uniform) {
-				RD::get_singleton()->free(state_data->state_uniform_set);
+			if (state_data->state_uniform_set_with_light.is_valid() && !invalid_uniform) {
+				RD::get_singleton()->free(canvas_item_state);
 			}
-			state_data->state_uniform_set = RID();
-
-			Vector<RD::Uniform> uniforms;
 
 			{
 				RD::Uniform u;
@@ -672,14 +595,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
 			} else {
 				//bind default
 
-				{
-					RD::Uniform u;
-					u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
-					u.binding = 0;
-					u.ids.push_back(state.canvas_state_buffer);
-					uniforms.push_back(u);
-				}
-
 				{
 					RD::Uniform u;
 					u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER;
@@ -697,19 +612,86 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
 				}
 			}
 
-			state_data->state_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, 2);
+			//validate and update lighs if they are being used
+
+			if (light_count > 0) {
+				//recreate uniform set
+
+				{
+					RD::Uniform u;
+					u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+					u.binding = 3;
+					u.ids.push_back(state.lights_uniform_buffer);
+					uniforms.push_back(u);
+				}
+
+				{
+
+					RD::Uniform u_lights;
+					u_lights.type = RD::UNIFORM_TYPE_TEXTURE;
+					u_lights.binding = 4;
+
+					RD::Uniform u_shadows;
+					u_shadows.type = RD::UNIFORM_TYPE_TEXTURE;
+					u_shadows.binding = 5;
+
+					//lights
+					for (uint32_t i = 0; i < state.max_lights_per_item; i++) {
+						if (i < light_count) {
+
+							CanvasLight *cl = canvas_light_owner.getornull(light_cache[i]->light_internal);
+							ERR_CONTINUE(!cl);
+
+							RID rd_texture;
+
+							if (cl->texture.is_valid()) {
+								rd_texture = storage->texture_get_rd_texture(cl->texture);
+							}
+							if (rd_texture.is_valid()) {
+								u_lights.ids.push_back(rd_texture);
+							} else {
+								u_lights.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+							}
+							if (cl->shadow.texture.is_valid()) {
+								u_shadows.ids.push_back(cl->shadow.texture);
+							} else {
+								u_shadows.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK));
+							}
+						} else {
+							u_lights.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+							u_shadows.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK));
+						}
+					}
+
+					uniforms.push_back(u_lights);
+					uniforms.push_back(u_shadows);
+				}
+
+				{
+					RD::Uniform u;
+					u.type = RD::UNIFORM_TYPE_SAMPLER;
+					u.binding = 6;
+					u.ids.push_back(state.shadow_sampler);
+					uniforms.push_back(u);
+				}
+
+				canvas_item_state = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader_light, 2);
+			} else {
+				canvas_item_state = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, 2);
+			}
 		}
 
-		RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, state_data->state_uniform_set, 2);
+		RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, canvas_item_state, 2);
 	}
 
-	PipelineVariants *pipeline_variants = &shader.pipeline_variants;
+	light_mode = light_count > 0 ? PIPELINE_LIGHT_MODE_ENABLED : PIPELINE_LIGHT_MODE_DISABLED;
+
+	PipelineVariants *pipeline_variants = p_pipeline_variants;
 
 	bool reclip = false;
 
 	const Item::Command *c = p_item->commands;
 	while (c) {
-
 		push_constant.flags = base_flags; //reset on each command for sanity
 		push_constant.specular_shininess = 0xFFFFFFFF;
 
@@ -1341,6 +1323,10 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count,
 
 	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, clear_colors);
 
+	RID prev_material;
+
+	PipelineVariants *pipeline_variants = &shader.pipeline_variants;
+
 	for (int i = 0; i < p_item_count; i++) {
 
 		Item *ci = items[i];
@@ -1360,7 +1346,34 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count,
 			}
 		}
 
-		_render_item(draw_list, ci, fb_format, canvas_transform_inverse, current_clip, p_lights);
+		if (ci->material != prev_material) {
+
+			MaterialData *material_data;
+			if (ci->material.is_valid()) {
+				material_data = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D);
+				print_line("has material data");
+			}
+
+			if (material_data) {
+
+				if (material_data->shader_data->version.is_valid()) {
+					pipeline_variants = &material_data->shader_data->pipeline_variants;
+					if (material_data->uniform_set.is_valid()) {
+						print_line("bound uniform set");
+						RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, 1);
+					}
+				} else {
+					pipeline_variants = &shader.pipeline_variants;
+				}
+			} else {
+				pipeline_variants = &shader.pipeline_variants;
+			}
+		}
+
+		print_line("go render");
+		_render_item(draw_list, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants);
+
+		prev_material = ci->material;
 	}
 
 	RD::get_singleton()->draw_list_end();
@@ -1397,6 +1410,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite
 		state_buffer.canvas_modulate[2] = p_modulate.b;
 		state_buffer.canvas_modulate[3] = p_modulate.a;
 
+		state_buffer.time = state.time;
 		RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true);
 	}
 
@@ -1462,26 +1476,46 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite
 	}
 
 	//fill the list until rendering is possible.
+	bool material_screen_texture_found = false;
 	Item *ci = p_item_list;
+	Rect2 back_buffer_rect;
+	bool backbuffer_copy = false;
+
 	while (ci) {
 
-		items[item_count++] = ci;
+		if (ci->copy_back_buffer) {
+			backbuffer_copy = true;
 
-		bool backbuffer_copy = ci->copy_back_buffer; // || shader uses SCREEN_TEXTURE
-		if (!ci->next || backbuffer_copy || item_count == MAX_RENDER_ITEMS - 1) {
+			if (ci->copy_back_buffer->full) {
+				back_buffer_rect = Rect2();
+			} else {
+				back_buffer_rect = ci->copy_back_buffer->rect;
+			}
+		}
+
+		if (!material_screen_texture_found && ci->material.is_valid()) {
+			MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D);
+			if (md->shader_data->uses_screen_texture) {
+				backbuffer_copy = true;
+				back_buffer_rect = Rect2();
+			}
+		}
+
+		if (backbuffer_copy) {
+			//render anything pending, including clearing if no items
 			_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
-			//then reset
 			item_count = 0;
-		}
 
-		if (ci->copy_back_buffer) {
+			backbuffer_copy = false;
+			material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies
+		}
 
-			if (ci->copy_back_buffer->full) {
+		items[item_count++] = ci;
 
-				//_copy_texscreen(Rect2());
-			} else {
-				//_copy_texscreen(ci->copy_back_buffer->rect);
-			}
+		if (!ci->next || item_count == MAX_RENDER_ITEMS - 1) {
+			_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+			//then reset
+			item_count = 0;
 		}
 
 		ci = ci->next;
@@ -1734,139 +1768,390 @@ void RasterizerCanvasRD::occluder_polygon_set_cull_mode(RID p_occluder, VS::Canv
 	oc->cull_mode = p_mode;
 }
 
-void RasterizerCanvasRD::update() {
-	_dispose_bindings();
-}
+void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) {
+	//compile
 
-RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
-	storage = p_storage;
+	print_line("shader set code?");
+	code = p_code;
+	valid = false;
+	ubo_size = 0;
+	uniforms.clear();
+	uses_screen_texture = false;
+	uses_material_samplers = false;
 
-	{ //create default textures
+	if (code == String()) {
+		return; //just invalid, but no error
+	}
 
-		RD::TextureFormat tformat;
-		tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
-		tformat.width = 4;
-		tformat.height = 4;
-		tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
-		tformat.type = RD::TEXTURE_TYPE_2D;
+	ShaderCompilerRD::GeneratedCode gen_code;
 
-		PoolVector<uint8_t> pv;
-		pv.resize(16 * 4);
-		for (int i = 0; i < 16; i++) {
-			pv.set(i * 4 + 0, 255);
-			pv.set(i * 4 + 1, 255);
-			pv.set(i * 4 + 2, 255);
-			pv.set(i * 4 + 3, 255);
+	int light_mode = LIGHT_MODE_NORMAL;
+	int blend_mode = BLEND_MODE_MIX;
+	bool uses_screen_texture = false;
+
+	ShaderCompilerRD::IdentifierActions actions;
+
+	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_PMALPHA);
+	actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_mode, BLEND_MODE_DISABLED);
+
+	actions.render_mode_values["unshaded"] = Pair<int *, int>(&light_mode, LIGHT_MODE_UNSHADED);
+	actions.render_mode_values["light_only"] = Pair<int *, int>(&light_mode, LIGHT_MODE_LIGHT_ONLY);
+
+	actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
+
+	actions.uniforms = &uniforms;
+
+	RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton;
+
+	Error err = canvas_singleton->shader.compiler.compile(VS::SHADER_CANVAS_ITEM, code, &actions, path, gen_code);
+
+	ERR_FAIL_COND(err != OK);
+
+	if (version.is_null()) {
+		version = canvas_singleton->shader.canvas_shader.version_create();
+	}
+
+	if (gen_code.texture_uniforms.size() || uses_screen_texture) { //requires the samplers
+		gen_code.defines.push_back("\n#define USE_MATERIAL_SAMPLERS\n");
+		uses_material_samplers = true;
+	}
+#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
+	canvas_singleton->shader.canvas_shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines);
+
+	ubo_size = gen_code.uniform_total_size;
+	ubo_offsets = gen_code.uniform_offsets;
+	texture_uniforms = gen_code.texture_uniforms;
+
+	//update them pipelines
+
+	RD::PipelineColorBlendState::Attachment attachment;
+
+	switch (blend_mode) {
+		case BLEND_MODE_DISABLED: {
+
+			// nothing to do here, disabled by default
+
+		} break;
+		case BLEND_MODE_MIX: {
+
+			attachment.enable_blend = true;
+			attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+			attachment.color_blend_op = RD::BLEND_OP_ADD;
+			attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+			attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+			attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+			attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+		} break;
+		case BLEND_MODE_ADD: {
+
+			attachment.enable_blend = true;
+			attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+			attachment.color_blend_op = RD::BLEND_OP_ADD;
+			attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+			attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+			attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+			attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+
+		} break;
+		case BLEND_MODE_SUB: {
+
+			attachment.enable_blend = true;
+			attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT;
+			attachment.color_blend_op = RD::BLEND_OP_SUBTRACT;
+			attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+			attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+			attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+			attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+
+		} break;
+		case BLEND_MODE_MUL: {
+			attachment.enable_blend = true;
+			attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+			attachment.color_blend_op = RD::BLEND_OP_ADD;
+			attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
+			attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
+			attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
+			attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+
+		} break;
+		case BLEND_MODE_PMALPHA: {
+			attachment.enable_blend = true;
+			attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+			attachment.color_blend_op = RD::BLEND_OP_ADD;
+			attachment.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
+			attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+			attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+			attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+		} break;
+	}
+
+	RD::PipelineColorBlendState blend_state;
+	blend_state.attachments.push_back(attachment);
+
+	//update pipelines
+
+	for (int i = 0; i < PIPELINE_LIGHT_MODE_MAX; i++) {
+		for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) {
+			RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = {
+				RD::RENDER_PRIMITIVE_TRIANGLES,
+				RD::RENDER_PRIMITIVE_TRIANGLES,
+				RD::RENDER_PRIMITIVE_TRIANGLES,
+				RD::RENDER_PRIMITIVE_LINES,
+				RD::RENDER_PRIMITIVE_POINTS,
+				RD::RENDER_PRIMITIVE_TRIANGLES,
+				RD::RENDER_PRIMITIVE_LINES,
+				RD::RENDER_PRIMITIVE_POINTS,
+			};
+			ShaderVariant shader_variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX] = {
+				{ //non lit
+						SHADER_VARIANT_QUAD,
+						SHADER_VARIANT_NINEPATCH,
+						SHADER_VARIANT_PRIMITIVE,
+						SHADER_VARIANT_PRIMITIVE,
+						SHADER_VARIANT_PRIMITIVE_POINTS,
+						SHADER_VARIANT_ATTRIBUTES,
+						SHADER_VARIANT_ATTRIBUTES,
+						SHADER_VARIANT_ATTRIBUTES_POINTS },
+				{ //lit
+						SHADER_VARIANT_QUAD_LIGHT,
+						SHADER_VARIANT_NINEPATCH_LIGHT,
+						SHADER_VARIANT_PRIMITIVE_LIGHT,
+						SHADER_VARIANT_PRIMITIVE_LIGHT,
+						SHADER_VARIANT_PRIMITIVE_POINTS_LIGHT,
+						SHADER_VARIANT_ATTRIBUTES_LIGHT,
+						SHADER_VARIANT_ATTRIBUTES_LIGHT,
+						SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT },
+			};
+
+			RID shader_variant = canvas_singleton->shader.canvas_shader.version_get_shader(version, shader_variants[i][j]);
+			pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
 		}
+	}
 
-		{
-			Vector<PoolVector<uint8_t> > vpv;
-			vpv.push_back(pv);
-			default_textures.white_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+	valid = true;
+}
+
+void RasterizerCanvasRD::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+	if (!p_texture.is_valid()) {
+		default_texture_params.erase(p_name);
+	} else {
+		default_texture_params[p_name] = p_texture;
+	}
+}
+void RasterizerCanvasRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+
+	Map<int, StringName> order;
+
+	for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+
+		if (E->get().texture_order >= 0) {
+			order[E->get().texture_order + 100000] = E->key();
+		} else {
+			order[E->get().order] = E->key();
 		}
+	}
+
+	for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
+
+		PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
+		pi.name = E->get();
+		p_param_list->push_back(pi);
+	}
+}
+
+bool RasterizerCanvasRD::ShaderData::is_param_texture(const StringName &p_param) const {
+	if (!uniforms.has(p_param)) {
+		return false;
+	}
+
+	return uniforms[p_param].texture_order >= 0;
+}
+
+bool RasterizerCanvasRD::ShaderData::is_animated() const {
+	return false;
+}
+bool RasterizerCanvasRD::ShaderData::casts_shadows() const {
+	return false;
+}
+Variant RasterizerCanvasRD::ShaderData::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.hint);
+	}
+	return Variant();
+}
+
+RasterizerCanvasRD::ShaderData::ShaderData() {
+	valid = false;
+	uses_screen_texture = false;
+	uses_material_samplers = false;
+}
+
+RasterizerCanvasRD::ShaderData::~ShaderData() {
+	RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton;
+	ERR_FAIL_COND(!canvas_singleton);
+	//pipeline variants will clear themselves if shader is gone
+	if (version.is_valid()) {
+		canvas_singleton->shader.canvas_shader.version_free(version);
+	}
+}
 
-		for (int i = 0; i < 16; i++) {
-			pv.set(i * 4 + 0, 0);
-			pv.set(i * 4 + 1, 0);
-			pv.set(i * 4 + 2, 0);
-			pv.set(i * 4 + 3, 255);
+RasterizerStorageRD::ShaderData *RasterizerCanvasRD::_create_shader_func() {
+	ShaderData *shader_data = memnew(ShaderData);
+	return shader_data;
+}
+void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+
+	RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton;
+
+	if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
+		p_uniform_dirty = true;
+		if (uniform_buffer.is_valid()) {
+			RD::get_singleton()->free(uniform_buffer);
+			uniform_buffer = RID();
 		}
 
-		{
-			Vector<PoolVector<uint8_t> > vpv;
-			vpv.push_back(pv);
-			default_textures.black_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+		ubo_data.resize(shader_data->ubo_size);
+		if (ubo_data.size()) {
+			uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
+			memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
 		}
 
-		for (int i = 0; i < 16; i++) {
-			pv.set(i * 4 + 0, 128);
-			pv.set(i * 4 + 1, 128);
-			pv.set(i * 4 + 2, 255);
-			pv.set(i * 4 + 3, 255);
+		//clear previous uniform set
+		if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+			RD::get_singleton()->free(uniform_set);
+			uniform_set = RID();
 		}
+	}
 
-		{
-			Vector<PoolVector<uint8_t> > vpv;
-			vpv.push_back(pv);
-			default_textures.normal_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+	//check whether buffer changed
+	if (p_uniform_dirty && ubo_data.size()) {
+
+		update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
+		RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw());
+	}
+
+	uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
+
+	if ((uint32_t)texture_cache.size() != tex_uniform_count) {
+		texture_cache.resize(tex_uniform_count);
+		p_textures_dirty = true;
+
+		//clear previous uniform set
+		if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+			RD::get_singleton()->free(uniform_set);
+			uniform_set = RID();
 		}
+	}
+
+	if (p_textures_dirty && tex_uniform_count) {
+
+		update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw());
+	}
+
+	if (shader_data->ubo_size == 0 && !shader_data->uses_material_samplers) {
+		// This material does not require an uniform set, so don't create it.
+		return;
+	}
+
+	if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+		//no reason to update uniform set, only UBO (or nothing) was needed to update
+		return;
+	}
 
-		for (int i = 0; i < 16; i++) {
-			pv.set(i * 4 + 0, 255);
-			pv.set(i * 4 + 1, 128);
-			pv.set(i * 4 + 2, 255);
-			pv.set(i * 4 + 3, 255);
+	Vector<RD::Uniform> uniforms;
+
+	{
+		if (shader_data->uses_material_samplers) {
+			//needs samplers for the material (uses custom textures) create them
+			RD::Uniform u;
+			u.type = RD::UNIFORM_TYPE_SAMPLER;
+			u.binding = 0;
+			u.ids.resize(12);
+			RID *ids_ptr = u.ids.ptrw();
+			ids_ptr[0] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+			ids_ptr[1] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+			ids_ptr[2] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+			ids_ptr[3] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+			ids_ptr[4] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+			ids_ptr[5] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+			ids_ptr[6] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+			ids_ptr[7] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+			ids_ptr[8] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+			ids_ptr[9] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+			ids_ptr[10] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+			ids_ptr[11] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+			uniforms.push_back(u);
 		}
 
-		{
-			Vector<PoolVector<uint8_t> > vpv;
-			vpv.push_back(pv);
-			default_textures.aniso_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+		if (shader_data->ubo_size) {
+			RD::Uniform u;
+			u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+			u.binding = 1;
+			u.ids.push_back(uniform_buffer);
+			uniforms.push_back(u);
 		}
 
-		for (int i = 0; i < 16; i++) {
-			pv.set(i * 4 + 0, 0);
-			pv.set(i * 4 + 1, 0);
-			pv.set(i * 4 + 2, 0);
-			pv.set(i * 4 + 3, 0);
+		const RID *textures = texture_cache.ptrw();
+		for (uint32_t i = 0; i < tex_uniform_count; i++) {
+			RD::Uniform u;
+			u.type = RD::UNIFORM_TYPE_TEXTURE;
+			u.binding = 2 + i;
+			u.ids.push_back(textures[i]);
+			uniforms.push_back(u);
 		}
+	}
 
-		default_textures.default_multimesh_tb = RD::get_singleton()->texture_buffer_create(16, RD::DATA_FORMAT_R8G8B8A8_UNORM, pv);
+	uniform_set = RD::get_singleton()->uniform_set_create(uniforms, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), 1);
+}
+RasterizerCanvasRD::MaterialData::~MaterialData() {
+	if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+		RD::get_singleton()->free(uniform_set);
 	}
 
-	{ //create default samplers
+	if (uniform_buffer.is_valid()) {
+		RD::get_singleton()->free(uniform_buffer);
+	}
+}
 
-		for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
-			for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
-				RD::SamplerState sampler_state;
-				switch (i) {
-					case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
-						sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
-						sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
-						sampler_state.max_lod = 0;
-					} break;
-					case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: {
-
-						sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
-						sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
-						sampler_state.max_lod = 0;
-					} break;
-					case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
-						sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
-						sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
-						sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
-
-					} break;
-					case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS: {
-						sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
-						sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
-						sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
-					} break;
-					default: {
-					}
-				}
-				switch (j) {
-					case VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {
-
-						sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
-						sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
-
-					} break;
-					case VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
-						sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT;
-						sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT;
-					} break;
-					case VS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
-						sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
-						sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
-					} break;
-					default: {
-					}
-				}
+RasterizerStorageRD::MaterialData *RasterizerCanvasRD::_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;
+}
 
-				default_samplers.samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state);
-			}
-		}
+void RasterizerCanvasRD::set_time(double p_time) {
+	state.time = p_time;
+}
+
+void RasterizerCanvasRD::update() {
+	_dispose_bindings();
+}
+
+RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
+	storage = p_storage;
+
+	{ //create default samplers
 
 		default_samplers.default_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
 		default_samplers.default_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
@@ -1963,6 +2248,66 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
 		}
 	}
 
+	{
+		//shader compiler
+		ShaderCompilerRD::DefaultIdentifierActions actions;
+
+		actions.renames["VERTEX"] = "vertex";
+		actions.renames["LIGHT_VERTEX"] = "light_vertex";
+		actions.renames["SHADOW_VERTEX"] = "shadow_vertex";
+		actions.renames["UV"] = "uv";
+		actions.renames["POINT_SIZE"] = "gl_PointSize";
+
+		actions.renames["WORLD_MATRIX"] = "world_matrix";
+		actions.renames["CANVAS_MATRIX"] = "canvas_data.canvas_transform";
+		actions.renames["SCREEN_MATRIX"] = "canvas_data.screen_transform";
+		actions.renames["TIME"] = "canvas_data.time";
+		actions.renames["AT_LIGHT_PASS"] = "false";
+		actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
+
+		actions.renames["COLOR"] = "color";
+		actions.renames["NORMAL"] = "normal";
+		actions.renames["NORMALMAP"] = "normal_map";
+		actions.renames["NORMALMAP_DEPTH"] = "normal_depth";
+		actions.renames["TEXTURE"] = "color_texture";
+		actions.renames["TEXTURE_PIXEL_SIZE"] = "draw_data.color_texture_pixel_size";
+		actions.renames["NORMAL_TEXTURE"] = "normal_texture";
+		actions.renames["SPECULAR_SHININESS_TEXTURE"] = "specular_texture";
+		actions.renames["SPECULAR_SHININESS"] = "specular_shininess";
+		actions.renames["SCREEN_UV"] = "screen_uv";
+		actions.renames["SCREEN_TEXTURE"] = "screen_texture";
+		actions.renames["SCREEN_PIXEL_SIZE"] = "canvas_data.screen_pixel_size";
+		actions.renames["FRAGCOORD"] = "gl_FragCoord";
+		actions.renames["POINT_COORD"] = "gl_PointCoord";
+
+		actions.renames["LIGHT_POSITION"] = "light_pos";
+		actions.renames["LIGHT_COLOR"] = "light_color";
+		actions.renames["LIGHT_ENERGY"] = "light_energy";
+		actions.renames["LIGHT"] = "light";
+		actions.renames["SHADOW_MODULATE"] = "shadow_modulate";
+
+		actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
+		actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+		actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+		actions.usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV";
+		actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
+		actions.usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n";
+		actions.usage_defines["LIGHT"] = "#define LIGHT_SHADER_CODE_USED\n";
+
+		actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+
+		actions.custom_samplers["TEXTURE"] = "texture_sampler";
+		actions.custom_samplers["NORMAL_TEXTURE"] = "texture_sampler";
+		actions.custom_samplers["SPECULAR_SHININESS_TEXTURE"] = "texture_sampler";
+		actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; //mipmap and filter for screen texture
+		actions.sampler_array_name = "material_samplers";
+		actions.base_texture_binding_index = 2;
+		actions.texture_layout_set = 1;
+		actions.base_uniform_string = "material.";
+
+		shader.compiler.initialize(actions);
+	}
+
 	{ //shadow rendering
 		Vector<String> versions;
 		versions.push_back(String()); //no versions
@@ -2122,6 +2467,12 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
 		shader.default_skeleton_texture_buffer = RD::get_singleton()->texture_buffer_create(32, RD::DATA_FORMAT_R32G32B32A32_SFLOAT);
 	}
 
+	//create functions for shader and material
+	storage->shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_2D, _create_shader_funcs);
+	storage->material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_2D, _create_material_funcs);
+
+	state.time = 0;
+
 	ERR_FAIL_COND(sizeof(PushConstant) != 128);
 }
 
@@ -2180,18 +2531,4 @@ RasterizerCanvasRD::~RasterizerCanvasRD() {
 	RD::get_singleton()->free(shader.quad_index_buffer);
 
 	//pipelines don't need freeing, they are all gone after shaders are gone
-
-	//samplers
-	for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
-		for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
-			RD::get_singleton()->free(default_samplers.samplers[i][j]);
-		}
-	}
-
-	//textures
-	RD::get_singleton()->free(default_textures.white_texture);
-	RD::get_singleton()->free(default_textures.black_texture);
-	RD::get_singleton()->free(default_textures.normal_texture);
-	RD::get_singleton()->free(default_textures.aniso_texture);
-	RD::get_singleton()->free(default_textures.default_multimesh_tb);
 }

+ 79 - 14
servers/visual/rasterizer/rasterizer_canvas_rd.h

@@ -4,6 +4,7 @@
 #include "servers/visual/rasterizer/rasterizer.h"
 #include "servers/visual/rasterizer/rasterizer_storage_rd.h"
 #include "servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.h"
+#include "servers/visual/rasterizer/shader_compiler_rd.h"
 #include "servers/visual/rasterizer/shaders/canvas.glsl.gen.h"
 #include "servers/visual/rasterizer/shaders/canvas_occlusion.glsl.gen.h"
 #include "servers/visual/rendering_device.h"
@@ -112,8 +113,77 @@ class RasterizerCanvasRD : public RasterizerCanvas {
 		RID default_skeleton_uniform_buffer;
 		RID default_skeleton_texture_buffer;
 
+		ShaderCompilerRD compiler;
 	} shader;
 
+	struct ShaderData : public RasterizerStorageRD::ShaderData {
+
+		enum BlendMode { //used internally
+			BLEND_MODE_MIX,
+			BLEND_MODE_ADD,
+			BLEND_MODE_SUB,
+			BLEND_MODE_MUL,
+			BLEND_MODE_PMALPHA,
+			BLEND_MODE_DISABLED,
+		};
+
+		enum LightMode {
+			LIGHT_MODE_NORMAL,
+			LIGHT_MODE_UNSHADED,
+			LIGHT_MODE_LIGHT_ONLY
+		};
+
+		bool valid;
+		RID version;
+		PipelineVariants pipeline_variants;
+		String path;
+
+		Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+		Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
+
+		Vector<uint32_t> ubo_offsets;
+		uint32_t ubo_size;
+
+		String code;
+		Map<StringName, RID> default_texture_params;
+
+		bool uses_screen_texture;
+		bool uses_material_samplers;
+
+		virtual void set_code(const String &p_Code);
+		virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
+		virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+		virtual 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;
+		ShaderData();
+		virtual ~ShaderData();
+	};
+
+	RasterizerStorageRD::ShaderData *_create_shader_func();
+	static RasterizerStorageRD::ShaderData *_create_shader_funcs() {
+		return static_cast<RasterizerCanvasRD *>(singleton)->_create_shader_func();
+	}
+
+	struct MaterialData : public RasterizerStorageRD::MaterialData {
+		ShaderData *shader_data;
+		RID uniform_buffer;
+		RID uniform_set;
+		Vector<RID> texture_cache;
+		Vector<uint8_t> ubo_data;
+
+		virtual void set_render_priority(int p_priority) {}
+		virtual void set_next_pass(RID p_pass) {}
+		virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+		virtual ~MaterialData();
+	};
+
+	RasterizerStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
+	static RasterizerStorageRD::MaterialData *_create_material_funcs(RasterizerStorageRD::ShaderData *p_shader) {
+		return static_cast<RasterizerCanvasRD *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
+	}
+
 	/**************************/
 	/**** TEXTURE BINDINGS ****/
 	/**************************/
@@ -168,18 +238,8 @@ class RasterizerCanvasRD : public RasterizerCanvas {
 
 	RID _create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh);
 	void _dispose_bindings();
-	struct {
-		RID white_texture;
-		RID black_texture;
-		RID normal_texture;
-		RID aniso_texture;
-
-		RID default_multimesh_tb;
-
-	} default_textures;
 
 	struct {
-		RID samplers[VS::CANVAS_ITEM_TEXTURE_FILTER_MAX][VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
 		VS::CanvasItemTextureFilter default_filter;
 		VS::CanvasItemTextureRepeat default_repeat;
 	} default_samplers;
@@ -293,7 +353,7 @@ class RasterizerCanvasRD : public RasterizerCanvas {
 
 		LightCache light_cache[DEFAULT_MAX_LIGHTS_PER_ITEM];
 		uint32_t light_cache_count;
-		RID light_uniform_set;
+		RID state_uniform_set_with_light;
 		RID state_uniform_set;
 		ItemStateData() {
 
@@ -305,8 +365,8 @@ class RasterizerCanvasRD : public RasterizerCanvas {
 		}
 
 		~ItemStateData() {
-			if (light_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(light_uniform_set)) {
-				RD::get_singleton()->free(light_uniform_set);
+			if (state_uniform_set_with_light.is_valid() && RD::get_singleton()->uniform_set_is_valid(state_uniform_set_with_light)) {
+				RD::get_singleton()->free(state_uniform_set_with_light);
 			}
 			if (state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state_uniform_set)) {
 				RD::get_singleton()->free(state_uniform_set);
@@ -322,6 +382,8 @@ class RasterizerCanvasRD : public RasterizerCanvas {
 			float screen_transform[16];
 			float canvas_normal_transform[16];
 			float canvas_modulate[4];
+			float time;
+			float pad[3];
 			//uint32_t light_count;
 			//uint32_t pad[3];
 		};
@@ -334,6 +396,8 @@ class RasterizerCanvasRD : public RasterizerCanvas {
 
 		uint32_t max_lights_per_render;
 		uint32_t max_lights_per_item;
+
+		double time;
 	} state;
 
 	struct PushConstant {
@@ -368,7 +432,7 @@ class RasterizerCanvasRD : public RasterizerCanvas {
 	Item *items[MAX_RENDER_ITEMS];
 
 	Size2i _bind_texture_binding(TextureBindingID p_binding, RenderingDevice::DrawListID p_draw_list, uint32_t &flags);
-	void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights);
+	void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants);
 	void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights);
 
 	_FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);
@@ -401,6 +465,7 @@ public:
 
 	void draw_window_margins(int *p_margins, RID *p_margin_textures) {}
 
+	void set_time(double p_time);
 	void update();
 	bool free(RID p_rid);
 	RasterizerCanvasRD(RasterizerStorageRD *p_storage);

+ 4 - 0
servers/visual/rasterizer/rasterizer_rd.cpp

@@ -46,9 +46,12 @@ void RasterizerRD::blit_render_targets_to_screen(int p_screen, const BlitToScree
 }
 
 void RasterizerRD::begin_frame(double frame_step) {
+	time += frame_step;
+	canvas->set_time(time);
 }
 
 void RasterizerRD::end_frame(bool p_swap_buffers) {
+
 	RD::get_singleton()->finalize_frame();
 #warning not swapping buffers likely not an option for now, find another way
 	OS::get_singleton()->swap_buffers(); //probably should pass some bool to avoid display?
@@ -130,6 +133,7 @@ void RasterizerRD::finalize() {
 }
 
 RasterizerRD::RasterizerRD() {
+	time = 0;
 	storage = memnew(RasterizerStorageRD);
 	canvas = memnew(RasterizerCanvasRD(storage));
 	scene = memnew(RasterizerSceneForwardRD);

+ 2 - 0
servers/visual/rasterizer/rasterizer_rd.h

@@ -20,6 +20,8 @@ protected:
 
 	Map<RID, RID> render_target_descriptors;
 
+	double time;
+
 public:
 	RasterizerStorage *get_storage() { return storage; }
 	RasterizerCanvas *get_canvas() { return canvas; }

+ 1056 - 0
servers/visual/rasterizer/rasterizer_storage_rd.cpp

@@ -1,5 +1,7 @@
 #include "rasterizer_storage_rd.h"
 #include "core/engine.h"
+#include "core/project_settings.h"
+#include "servers/visual/shader_language.h"
 
 Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) {
 
@@ -775,6 +777,878 @@ Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) {
 	return texture_2d_get_size(p_proxy);
 }
 
+/* SHADER API */
+
+RID RasterizerStorageRD::shader_create() {
+
+	Shader shader;
+	shader.data = NULL;
+	shader.type = SHADER_TYPE_MAX;
+
+	return shader_owner.make_rid(shader);
+}
+
+void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) {
+	Shader *shader = shader_owner.getornull(p_shader);
+	ERR_FAIL_COND(!shader);
+
+	print_line("yey set code?");
+	shader->code = p_code;
+	String mode_string = ShaderLanguage::get_shader_type(p_code);
+
+	ShaderType new_type;
+	if (mode_string == "canvas_item")
+		new_type = SHADER_TYPE_2D;
+	else if (mode_string == "particles")
+		new_type = SHADER_TYPE_PARTICLES;
+	else if (mode_string == "spatial")
+		new_type = SHADER_TYPE_3D;
+	else
+		new_type = SHADER_TYPE_MAX;
+
+	if (new_type != shader->type) {
+		if (shader->data) {
+			memdelete(shader->data);
+			shader->data = NULL;
+		}
+
+		for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
+
+			Material *material = E->get();
+			material->shader_type = new_type;
+			if (material->data) {
+				memdelete(material->data);
+				material->data = NULL;
+			}
+		}
+
+		shader->type = new_type;
+
+		if (new_type < SHADER_TYPE_MAX && shader_data_request_func[new_type]) {
+			shader->data = shader_data_request_func[new_type]();
+		} else {
+			shader->type = SHADER_TYPE_MAX; //invalid
+		}
+
+		for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
+			Material *material = E->get();
+			if (shader->data) {
+				material->data = material_data_request_func[new_type](shader->data);
+				material->data->set_next_pass(material->next_pass);
+				material->data->set_render_priority(material->priority);
+			}
+			material->shader_type = new_type;
+		}
+	}
+
+	if (shader->data) {
+		shader->data->set_code(p_code);
+	}
+
+	for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
+		Material *material = E->get();
+		material->instance_dependency.instance_notify_changed(false, true);
+		_material_queue_update(material, true, true);
+	}
+}
+
+String RasterizerStorageRD::shader_get_code(RID p_shader) const {
+	Shader *shader = shader_owner.getornull(p_shader);
+	ERR_FAIL_COND_V(!shader, String());
+	return shader->code;
+}
+void RasterizerStorageRD::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
+
+	Shader *shader = shader_owner.getornull(p_shader);
+	ERR_FAIL_COND(!shader);
+	if (shader->data) {
+		return shader->data->get_param_list(p_param_list);
+	}
+}
+
+void RasterizerStorageRD::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) {
+
+	Shader *shader = shader_owner.getornull(p_shader);
+	ERR_FAIL_COND(!shader);
+
+	if (p_texture.is_valid() && texture_owner.owns(p_texture)) {
+		shader->default_texture_parameter[p_name] = p_texture;
+	} else {
+		shader->default_texture_parameter.erase(p_name);
+	}
+
+	for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
+		Material *material = E->get();
+		_material_queue_update(material, false, true);
+	}
+}
+
+RID RasterizerStorageRD::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const {
+	Shader *shader = shader_owner.getornull(p_shader);
+	ERR_FAIL_COND_V(!shader, RID());
+	if (shader->default_texture_parameter.has(p_name)) {
+		return shader->default_texture_parameter[p_name];
+	}
+
+	return RID();
+}
+Variant RasterizerStorageRD::shader_get_param_default(RID p_shader, const StringName &p_param) const {
+	Shader *shader = shader_owner.getornull(p_shader);
+	ERR_FAIL_COND_V(!shader, Variant());
+	if (shader->data) {
+		return shader->data->get_default_parameter(p_param);
+	}
+	return Variant();
+}
+void RasterizerStorageRD::shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function) {
+	ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX);
+	shader_data_request_func[p_shader_type] = p_function;
+}
+
+/* COMMON MATERIAL API */
+
+RID RasterizerStorageRD::material_create() {
+	Material material;
+	material.data = NULL;
+	material.shader = NULL;
+	material.shader_type = SHADER_TYPE_MAX;
+	material.update_next = NULL;
+	material.update_requested = false;
+	material.uniform_dirty = false;
+	material.texture_dirty = false;
+	material.priority = 0;
+	RID id = material_owner.make_rid(material);
+	{
+		Material *material_ptr = material_owner.getornull(id);
+		material_ptr->self = id;
+	}
+	return id;
+}
+
+void RasterizerStorageRD::_material_queue_update(Material *material, bool p_uniform, bool p_texture) {
+	if (material->update_requested) {
+		return;
+	}
+
+	material->update_next = material_update_list;
+	material_update_list = material;
+	material->update_requested = true;
+	material->uniform_dirty = p_uniform;
+	material->texture_dirty = p_texture;
+}
+
+void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) {
+
+	Material *material = material_owner.getornull(p_material);
+	ERR_FAIL_COND(!material);
+
+	if (material->data) {
+		memdelete(material->data);
+		material->data = NULL;
+	}
+
+	if (material->shader) {
+		material->shader->owners.erase(material);
+		material->shader = NULL;
+		material->shader_type = SHADER_TYPE_MAX;
+	}
+
+	if (p_shader.is_null()) {
+		material->instance_dependency.instance_notify_changed(false, true);
+		return;
+	}
+
+	Shader *shader = shader_owner.getornull(p_shader);
+	ERR_FAIL_COND(!shader);
+	material->shader = shader;
+	material->shader_type = shader->type;
+	shader->owners.insert(material);
+
+	if (shader->type == SHADER_TYPE_MAX) {
+		return;
+	}
+
+	ERR_FAIL_COND(shader->data == NULL);
+
+	material->data = material_data_request_func[shader->type](shader->data);
+	material->data->set_next_pass(material->next_pass);
+	material->data->set_render_priority(material->priority);
+	//updating happens later
+	material->instance_dependency.instance_notify_changed(false, true);
+	_material_queue_update(material, true, true);
+}
+
+void RasterizerStorageRD::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) {
+
+	Material *material = material_owner.getornull(p_material);
+	ERR_FAIL_COND(!material);
+
+	if (p_value.get_type() == Variant::NIL) {
+		material->params.erase(p_param);
+	} else {
+		material->params[p_param] = p_value;
+	}
+
+	if (material->shader && material->shader->data) { //shader is valid
+		bool is_texture = material->shader->data->is_param_texture(p_param);
+		_material_queue_update(material, !is_texture, is_texture);
+	} else {
+		_material_queue_update(material, true, true);
+	}
+}
+
+Variant RasterizerStorageRD::material_get_param(RID p_material, const StringName &p_param) const {
+	Material *material = material_owner.getornull(p_material);
+	ERR_FAIL_COND_V(!material, Variant());
+	if (material->params.has(p_param)) {
+		return material->params[p_param];
+	} else {
+		return Variant();
+	}
+}
+
+void RasterizerStorageRD::material_set_next_pass(RID p_material, RID p_next_material) {
+	Material *material = material_owner.getornull(p_material);
+	ERR_FAIL_COND(!material);
+
+	if (material->next_pass == p_next_material) {
+		return;
+	}
+
+	material->next_pass = p_next_material;
+	if (material->data) {
+		material->data->set_next_pass(p_next_material);
+	}
+
+	material->instance_dependency.instance_notify_changed(false, true);
+}
+void RasterizerStorageRD::material_set_render_priority(RID p_material, int priority) {
+	Material *material = material_owner.getornull(p_material);
+	ERR_FAIL_COND(!material);
+	material->priority = priority;
+	if (material->data) {
+		material->data->set_render_priority(priority);
+	}
+}
+
+bool RasterizerStorageRD::material_is_animated(RID p_material) {
+	Material *material = material_owner.getornull(p_material);
+	ERR_FAIL_COND_V(!material, false);
+	if (material->shader && material->shader->data) {
+		if (material->shader->data->is_animated()) {
+			return true;
+		} else if (material->next_pass.is_valid()) {
+			return material_is_animated(material->next_pass);
+		}
+	}
+	return false; //by default nothing is animated
+}
+bool RasterizerStorageRD::material_casts_shadows(RID p_material) {
+	Material *material = material_owner.getornull(p_material);
+	ERR_FAIL_COND_V(!material, true);
+	if (material->shader && material->shader->data) {
+		if (material->shader->data->casts_shadows()) {
+			return true;
+		} else if (material->next_pass.is_valid()) {
+			return material_casts_shadows(material->next_pass);
+		}
+	}
+	return true; //by default everything casts shadows
+}
+
+void RasterizerStorageRD::material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) {
+	Material *material = material_owner.getornull(p_material);
+	ERR_FAIL_COND(!material);
+	p_instance->update_dependency(&material->instance_dependency);
+	if (material->next_pass.is_valid()) {
+		material_update_dependency(material->next_pass, p_instance);
+	}
+}
+
+void RasterizerStorageRD::material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function) {
+	ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX);
+	material_data_request_func[p_shader_type] = p_function;
+}
+
+_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant &value, uint8_t *data, bool p_linear_color) {
+	switch (type) {
+		case ShaderLanguage::TYPE_BOOL: {
+
+			bool v = value;
+
+			uint32_t *gui = (uint32_t *)data;
+			*gui = v ? 1 : 0;
+		} break;
+		case ShaderLanguage::TYPE_BVEC2: {
+
+			int v = value;
+			uint32_t *gui = (uint32_t *)data;
+			gui[0] = v & 1 ? 1 : 0;
+			gui[1] = v & 2 ? 1 : 0;
+
+		} break;
+		case ShaderLanguage::TYPE_BVEC3: {
+
+			int v = value;
+			uint32_t *gui = (uint32_t *)data;
+			gui[0] = (v & 1) ? 1 : 0;
+			gui[1] = (v & 2) ? 1 : 0;
+			gui[2] = (v & 4) ? 1 : 0;
+
+		} break;
+		case ShaderLanguage::TYPE_BVEC4: {
+
+			int v = value;
+			uint32_t *gui = (uint32_t *)data;
+			gui[0] = (v & 1) ? 1 : 0;
+			gui[1] = (v & 2) ? 1 : 0;
+			gui[2] = (v & 4) ? 1 : 0;
+			gui[3] = (v & 8) ? 1 : 0;
+
+		} break;
+		case ShaderLanguage::TYPE_INT: {
+
+			int v = value;
+			int32_t *gui = (int32_t *)data;
+			gui[0] = v;
+
+		} break;
+		case ShaderLanguage::TYPE_IVEC2: {
+
+			PoolVector<int> iv = value;
+			int s = iv.size();
+			int32_t *gui = (int32_t *)data;
+
+			PoolVector<int>::Read r = iv.read();
+
+			for (int i = 0; i < 2; i++) {
+				if (i < s)
+					gui[i] = r[i];
+				else
+					gui[i] = 0;
+			}
+
+		} break;
+		case ShaderLanguage::TYPE_IVEC3: {
+
+			PoolVector<int> iv = value;
+			int s = iv.size();
+			int32_t *gui = (int32_t *)data;
+
+			PoolVector<int>::Read r = iv.read();
+
+			for (int i = 0; i < 3; i++) {
+				if (i < s)
+					gui[i] = r[i];
+				else
+					gui[i] = 0;
+			}
+		} break;
+		case ShaderLanguage::TYPE_IVEC4: {
+
+			PoolVector<int> iv = value;
+			int s = iv.size();
+			int32_t *gui = (int32_t *)data;
+
+			PoolVector<int>::Read r = iv.read();
+
+			for (int i = 0; i < 4; i++) {
+				if (i < s)
+					gui[i] = r[i];
+				else
+					gui[i] = 0;
+			}
+		} break;
+		case ShaderLanguage::TYPE_UINT: {
+
+			int v = value;
+			uint32_t *gui = (uint32_t *)data;
+			gui[0] = v;
+
+		} break;
+		case ShaderLanguage::TYPE_UVEC2: {
+
+			PoolVector<int> iv = value;
+			int s = iv.size();
+			uint32_t *gui = (uint32_t *)data;
+
+			PoolVector<int>::Read r = iv.read();
+
+			for (int i = 0; i < 2; i++) {
+				if (i < s)
+					gui[i] = r[i];
+				else
+					gui[i] = 0;
+			}
+		} break;
+		case ShaderLanguage::TYPE_UVEC3: {
+			PoolVector<int> iv = value;
+			int s = iv.size();
+			uint32_t *gui = (uint32_t *)data;
+
+			PoolVector<int>::Read r = iv.read();
+
+			for (int i = 0; i < 3; i++) {
+				if (i < s)
+					gui[i] = r[i];
+				else
+					gui[i] = 0;
+			}
+
+		} break;
+		case ShaderLanguage::TYPE_UVEC4: {
+			PoolVector<int> iv = value;
+			int s = iv.size();
+			uint32_t *gui = (uint32_t *)data;
+
+			PoolVector<int>::Read r = iv.read();
+
+			for (int i = 0; i < 4; i++) {
+				if (i < s)
+					gui[i] = r[i];
+				else
+					gui[i] = 0;
+			}
+		} break;
+		case ShaderLanguage::TYPE_FLOAT: {
+			float v = value;
+			float *gui = (float *)data;
+			gui[0] = v;
+
+		} break;
+		case ShaderLanguage::TYPE_VEC2: {
+			Vector2 v = value;
+			float *gui = (float *)data;
+			gui[0] = v.x;
+			gui[1] = v.y;
+
+		} break;
+		case ShaderLanguage::TYPE_VEC3: {
+			Vector3 v = value;
+			float *gui = (float *)data;
+			gui[0] = v.x;
+			gui[1] = v.y;
+			gui[2] = v.z;
+
+		} break;
+		case ShaderLanguage::TYPE_VEC4: {
+
+			float *gui = (float *)data;
+
+			if (value.get_type() == Variant::COLOR) {
+				Color v = value;
+
+				if (p_linear_color) {
+					v = v.to_linear();
+				}
+
+				gui[0] = v.r;
+				gui[1] = v.g;
+				gui[2] = v.b;
+				gui[3] = v.a;
+			} else if (value.get_type() == Variant::RECT2) {
+				Rect2 v = value;
+
+				gui[0] = v.position.x;
+				gui[1] = v.position.y;
+				gui[2] = v.size.x;
+				gui[3] = v.size.y;
+			} else if (value.get_type() == Variant::QUAT) {
+				Quat v = value;
+
+				gui[0] = v.x;
+				gui[1] = v.y;
+				gui[2] = v.z;
+				gui[3] = v.w;
+			} else {
+				Plane v = value;
+
+				gui[0] = v.normal.x;
+				gui[1] = v.normal.y;
+				gui[2] = v.normal.z;
+				gui[3] = v.d;
+			}
+		} break;
+		case ShaderLanguage::TYPE_MAT2: {
+			Transform2D v = value;
+			float *gui = (float *)data;
+
+			//in std140 members of mat2 are treated as vec4s
+			gui[0] = v.elements[0][0];
+			gui[1] = v.elements[0][1];
+			gui[2] = 0;
+			gui[3] = 0;
+			gui[4] = v.elements[1][0];
+			gui[5] = v.elements[1][1];
+			gui[6] = 0;
+			gui[7] = 0;
+		} break;
+		case ShaderLanguage::TYPE_MAT3: {
+
+			Basis v = value;
+			float *gui = (float *)data;
+
+			gui[0] = v.elements[0][0];
+			gui[1] = v.elements[1][0];
+			gui[2] = v.elements[2][0];
+			gui[3] = 0;
+			gui[4] = v.elements[0][1];
+			gui[5] = v.elements[1][1];
+			gui[6] = v.elements[2][1];
+			gui[7] = 0;
+			gui[8] = v.elements[0][2];
+			gui[9] = v.elements[1][2];
+			gui[10] = v.elements[2][2];
+			gui[11] = 0;
+		} break;
+		case ShaderLanguage::TYPE_MAT4: {
+
+			Transform v = value;
+			float *gui = (float *)data;
+
+			gui[0] = v.basis.elements[0][0];
+			gui[1] = v.basis.elements[1][0];
+			gui[2] = v.basis.elements[2][0];
+			gui[3] = 0;
+			gui[4] = v.basis.elements[0][1];
+			gui[5] = v.basis.elements[1][1];
+			gui[6] = v.basis.elements[2][1];
+			gui[7] = 0;
+			gui[8] = v.basis.elements[0][2];
+			gui[9] = v.basis.elements[1][2];
+			gui[10] = v.basis.elements[2][2];
+			gui[11] = 0;
+			gui[12] = v.origin.x;
+			gui[13] = v.origin.y;
+			gui[14] = v.origin.z;
+			gui[15] = 1;
+		} break;
+		default: {
+		}
+	}
+}
+
+_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::ConstantNode::Value> &value, uint8_t *data) {
+
+	switch (type) {
+		case ShaderLanguage::TYPE_BOOL: {
+
+			uint32_t *gui = (uint32_t *)data;
+			*gui = value[0].boolean ? 1 : 0;
+		} break;
+		case ShaderLanguage::TYPE_BVEC2: {
+
+			uint32_t *gui = (uint32_t *)data;
+			gui[0] = value[0].boolean ? 1 : 0;
+			gui[1] = value[1].boolean ? 1 : 0;
+
+		} break;
+		case ShaderLanguage::TYPE_BVEC3: {
+
+			uint32_t *gui = (uint32_t *)data;
+			gui[0] = value[0].boolean ? 1 : 0;
+			gui[1] = value[1].boolean ? 1 : 0;
+			gui[2] = value[2].boolean ? 1 : 0;
+
+		} break;
+		case ShaderLanguage::TYPE_BVEC4: {
+
+			uint32_t *gui = (uint32_t *)data;
+			gui[0] = value[0].boolean ? 1 : 0;
+			gui[1] = value[1].boolean ? 1 : 0;
+			gui[2] = value[2].boolean ? 1 : 0;
+			gui[3] = value[3].boolean ? 1 : 0;
+
+		} break;
+		case ShaderLanguage::TYPE_INT: {
+
+			int32_t *gui = (int32_t *)data;
+			gui[0] = value[0].sint;
+
+		} break;
+		case ShaderLanguage::TYPE_IVEC2: {
+
+			int32_t *gui = (int32_t *)data;
+
+			for (int i = 0; i < 2; i++) {
+				gui[i] = value[i].sint;
+			}
+
+		} break;
+		case ShaderLanguage::TYPE_IVEC3: {
+
+			int32_t *gui = (int32_t *)data;
+
+			for (int i = 0; i < 3; i++) {
+				gui[i] = value[i].sint;
+			}
+
+		} break;
+		case ShaderLanguage::TYPE_IVEC4: {
+
+			int32_t *gui = (int32_t *)data;
+
+			for (int i = 0; i < 4; i++) {
+				gui[i] = value[i].sint;
+			}
+
+		} break;
+		case ShaderLanguage::TYPE_UINT: {
+
+			uint32_t *gui = (uint32_t *)data;
+			gui[0] = value[0].uint;
+
+		} break;
+		case ShaderLanguage::TYPE_UVEC2: {
+
+			int32_t *gui = (int32_t *)data;
+
+			for (int i = 0; i < 2; i++) {
+				gui[i] = value[i].uint;
+			}
+		} break;
+		case ShaderLanguage::TYPE_UVEC3: {
+			int32_t *gui = (int32_t *)data;
+
+			for (int i = 0; i < 3; i++) {
+				gui[i] = value[i].uint;
+			}
+
+		} break;
+		case ShaderLanguage::TYPE_UVEC4: {
+			int32_t *gui = (int32_t *)data;
+
+			for (int i = 0; i < 4; i++) {
+				gui[i] = value[i].uint;
+			}
+		} break;
+		case ShaderLanguage::TYPE_FLOAT: {
+
+			float *gui = (float *)data;
+			gui[0] = value[0].real;
+
+		} break;
+		case ShaderLanguage::TYPE_VEC2: {
+
+			float *gui = (float *)data;
+
+			for (int i = 0; i < 2; i++) {
+				gui[i] = value[i].real;
+			}
+
+		} break;
+		case ShaderLanguage::TYPE_VEC3: {
+
+			float *gui = (float *)data;
+
+			for (int i = 0; i < 3; i++) {
+				gui[i] = value[i].real;
+			}
+
+		} break;
+		case ShaderLanguage::TYPE_VEC4: {
+
+			float *gui = (float *)data;
+
+			for (int i = 0; i < 4; i++) {
+				gui[i] = value[i].real;
+			}
+		} break;
+		case ShaderLanguage::TYPE_MAT2: {
+			float *gui = (float *)data;
+
+			//in std140 members of mat2 are treated as vec4s
+			gui[0] = value[0].real;
+			gui[1] = value[1].real;
+			gui[2] = 0;
+			gui[3] = 0;
+			gui[4] = value[2].real;
+			gui[5] = value[3].real;
+			gui[6] = 0;
+			gui[7] = 0;
+		} break;
+		case ShaderLanguage::TYPE_MAT3: {
+
+			float *gui = (float *)data;
+
+			gui[0] = value[0].real;
+			gui[1] = value[1].real;
+			gui[2] = value[2].real;
+			gui[3] = 0;
+			gui[4] = value[3].real;
+			gui[5] = value[4].real;
+			gui[6] = value[5].real;
+			gui[7] = 0;
+			gui[8] = value[6].real;
+			gui[9] = value[7].real;
+			gui[10] = value[8].real;
+			gui[11] = 0;
+		} break;
+		case ShaderLanguage::TYPE_MAT4: {
+
+			float *gui = (float *)data;
+
+			for (int i = 0; i < 16; i++) {
+				gui[i] = value[i].real;
+			}
+		} break;
+		default: {
+		}
+	}
+}
+
+_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, uint8_t *data) {
+
+	switch (type) {
+
+		case ShaderLanguage::TYPE_BOOL:
+		case ShaderLanguage::TYPE_INT:
+		case ShaderLanguage::TYPE_UINT:
+		case ShaderLanguage::TYPE_FLOAT: {
+			zeromem(data, 4);
+		} break;
+		case ShaderLanguage::TYPE_BVEC2:
+		case ShaderLanguage::TYPE_IVEC2:
+		case ShaderLanguage::TYPE_UVEC2:
+		case ShaderLanguage::TYPE_VEC2: {
+			zeromem(data, 8);
+		} break;
+		case ShaderLanguage::TYPE_BVEC3:
+		case ShaderLanguage::TYPE_IVEC3:
+		case ShaderLanguage::TYPE_UVEC3:
+		case ShaderLanguage::TYPE_VEC3:
+		case ShaderLanguage::TYPE_BVEC4:
+		case ShaderLanguage::TYPE_IVEC4:
+		case ShaderLanguage::TYPE_UVEC4:
+		case ShaderLanguage::TYPE_VEC4: {
+
+			zeromem(data, 16);
+		} break;
+		case ShaderLanguage::TYPE_MAT2: {
+
+			zeromem(data, 32);
+		} break;
+		case ShaderLanguage::TYPE_MAT3: {
+
+			zeromem(data, 48);
+		} break;
+		case ShaderLanguage::TYPE_MAT4: {
+			zeromem(data, 64);
+		} break;
+
+		default: {
+		}
+	}
+}
+
+void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) {
+
+	for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = p_uniforms.front(); E; E = E->next()) {
+
+		if (E->get().order < 0)
+			continue; // texture, does not go here
+
+		//regular uniform
+		uint32_t offset = p_uniform_offsets[E->get().order];
+#ifdef DEBUG_ENABLED
+		uint32_t size = ShaderLanguage::get_type_size(E->get().type);
+		ERR_CONTINUE(offset + size > p_buffer_size);
+#endif
+		uint8_t *data = &p_buffer[offset];
+		const Map<StringName, Variant>::Element *V = p_parameters.find(E->key());
+
+		if (V) {
+			//user provided
+			_fill_std140_variant_ubo_value(E->get().type, V->get(), data, p_use_linear_color);
+
+		} else if (E->get().default_value.size()) {
+			//default value
+			_fill_std140_ubo_value(E->get().type, E->get().default_value, data);
+			//value=E->get().default_value;
+		} else {
+			//zero because it was not provided
+			if (E->get().type == ShaderLanguage::TYPE_VEC4 && E->get().hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+				//colors must be set as black, with alpha as 1.0
+				_fill_std140_variant_ubo_value(E->get().type, Color(0, 0, 0, 1), data, p_use_linear_color);
+			} else {
+				//else just zero it out
+				_fill_std140_ubo_empty(E->get().type, data);
+			}
+		}
+	}
+}
+
+void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures) {
+
+	RasterizerStorageRD *singleton = (RasterizerStorageRD *)RasterizerStorage::base_singleton;
+
+	for (int i = 0; i < p_texture_uniforms.size(); i++) {
+
+		const StringName &uniform_name = p_texture_uniforms[i].name;
+
+		RID texture;
+
+		const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name);
+		if (V) {
+			texture = V->get();
+		}
+
+		if (!texture.is_valid()) {
+			const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name);
+			if (W) {
+				texture = W->get();
+			}
+		}
+
+		RID rd_texture;
+
+		if (texture.is_null()) {
+			//check default usage
+			switch (p_texture_uniforms[i].hint) {
+				case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK:
+				case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: {
+					rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK);
+				} break;
+				case ShaderLanguage::ShaderNode::Uniform::HINT_NONE: {
+					rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL);
+				} break;
+				case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: {
+					rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO);
+				} break;
+				default: {
+					rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
+				} break;
+			}
+		} else {
+			bool srgb = p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO;
+			rd_texture = singleton->texture_get_rd_texture(texture, srgb);
+			if (rd_texture.is_null()) {
+				//wtf
+				rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
+			}
+		}
+
+		p_textures[i] = rd_texture;
+	}
+}
+
+void RasterizerStorageRD::_update_queued_materials() {
+	Material *material = material_update_list;
+	while (material) {
+		Material *next = material->update_next;
+
+		if (material->data) {
+			material->data->update_parameters(material->params, material->uniform_dirty, material->texture_dirty);
+		}
+		material->update_requested = false;
+		material->texture_dirty = false;
+		material->uniform_dirty = false;
+		material->update_next = NULL;
+		material = next;
+	}
+	material_update_list = NULL;
+}
+
 /* RENDER TARGET API */
 
 void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {
@@ -992,6 +1866,10 @@ void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) {
 	rt->clear_requested = false;
 }
 
+void RasterizerStorageRD::update_dirty_resources() {
+	_update_queued_materials();
+}
+
 bool RasterizerStorageRD::free(RID p_rid) {
 
 	if (texture_owner.owns(p_rid)) {
@@ -1014,6 +1892,25 @@ bool RasterizerStorageRD::free(RID p_rid) {
 		}
 		texture_owner.free(p_rid);
 
+	} else if (shader_owner.owns(p_rid)) {
+		Shader *shader = shader_owner.getornull(p_rid);
+		//make material unreference this
+		while (shader->owners.size()) {
+			material_set_shader(shader->owners.front()->get()->self, RID());
+		}
+		//clear data if exists
+		if (shader->data) {
+			memdelete(shader->data);
+		}
+		shader_owner.free(p_rid);
+
+	} else if (material_owner.owns(p_rid)) {
+		Material *material = material_owner.getornull(p_rid);
+		if (material->update_requested) {
+			_update_queued_materials();
+		}
+		material_set_shader(p_rid, RID()); //clean up shader
+		material->instance_dependency.instance_notify_deleted(p_rid);
 	} else if (render_target_owner.owns(p_rid)) {
 		RenderTarget *rt = render_target_owner.getornull(p_rid);
 
@@ -1032,3 +1929,162 @@ bool RasterizerStorageRD::free(RID p_rid) {
 
 	return true;
 }
+
+RasterizerStorageRD::RasterizerStorageRD() {
+
+	material_update_list = NULL;
+	{ //create default textures
+
+		RD::TextureFormat tformat;
+		tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+		tformat.width = 4;
+		tformat.height = 4;
+		tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
+		tformat.type = RD::TEXTURE_TYPE_2D;
+
+		PoolVector<uint8_t> pv;
+		pv.resize(16 * 4);
+		for (int i = 0; i < 16; i++) {
+			pv.set(i * 4 + 0, 255);
+			pv.set(i * 4 + 1, 255);
+			pv.set(i * 4 + 2, 255);
+			pv.set(i * 4 + 3, 255);
+		}
+
+		{
+			Vector<PoolVector<uint8_t> > vpv;
+			vpv.push_back(pv);
+			default_rd_textures[DEFAULT_RD_TEXTURE_WHITE] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+		}
+
+		for (int i = 0; i < 16; i++) {
+			pv.set(i * 4 + 0, 0);
+			pv.set(i * 4 + 1, 0);
+			pv.set(i * 4 + 2, 0);
+			pv.set(i * 4 + 3, 255);
+		}
+
+		{
+			Vector<PoolVector<uint8_t> > vpv;
+			vpv.push_back(pv);
+			default_rd_textures[DEFAULT_RD_TEXTURE_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+		}
+
+		for (int i = 0; i < 16; i++) {
+			pv.set(i * 4 + 0, 128);
+			pv.set(i * 4 + 1, 128);
+			pv.set(i * 4 + 2, 255);
+			pv.set(i * 4 + 3, 255);
+		}
+
+		{
+			Vector<PoolVector<uint8_t> > vpv;
+			vpv.push_back(pv);
+			default_rd_textures[DEFAULT_RD_TEXTURE_NORMAL] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+		}
+
+		for (int i = 0; i < 16; i++) {
+			pv.set(i * 4 + 0, 255);
+			pv.set(i * 4 + 1, 128);
+			pv.set(i * 4 + 2, 255);
+			pv.set(i * 4 + 3, 255);
+		}
+
+		{
+			Vector<PoolVector<uint8_t> > vpv;
+			vpv.push_back(pv);
+			default_rd_textures[DEFAULT_RD_TEXTURE_ANISO] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+		}
+
+		for (int i = 0; i < 16; i++) {
+			pv.set(i * 4 + 0, 0);
+			pv.set(i * 4 + 1, 0);
+			pv.set(i * 4 + 2, 0);
+			pv.set(i * 4 + 3, 0);
+		}
+
+		default_rd_textures[DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER] = RD::get_singleton()->texture_buffer_create(16, RD::DATA_FORMAT_R8G8B8A8_UNORM, pv);
+	}
+
+	//default samplers
+	for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
+		for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
+			RD::SamplerState sampler_state;
+			switch (i) {
+				case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
+					sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+					sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+					sampler_state.max_lod = 0;
+				} break;
+				case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: {
+
+					sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+					sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+					sampler_state.max_lod = 0;
+				} break;
+				case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS: {
+					sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+					sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+					sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+				} break;
+				case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
+					sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+					sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+					sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+
+				} break;
+				case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC: {
+					sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+					sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+					sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+					sampler_state.use_anisotropy = true;
+					sampler_state.anisotropy_max = GLOBAL_GET("rendering/quality/filters/max_anisotropy");
+				} break;
+				case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: {
+					sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+					sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+					sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+					sampler_state.use_anisotropy = true;
+					sampler_state.anisotropy_max = GLOBAL_GET("rendering/quality/filters/max_anisotropy");
+
+				} break;
+				default: {
+				}
+			}
+			switch (j) {
+				case VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {
+
+					sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+					sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+
+				} break;
+				case VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
+					sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT;
+					sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT;
+				} break;
+				case VS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
+					sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+					sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+				} break;
+				default: {
+				}
+			}
+
+			default_rd_samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state);
+		}
+	}
+}
+
+RasterizerStorageRD::~RasterizerStorageRD() {
+	//def textures
+	for (int i = 0; i < DEFAULT_RD_TEXTURE_MAX; i++) {
+		RD::get_singleton()->free(default_rd_textures[i]);
+	}
+
+	//def samplers
+	for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
+		for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
+			RD::get_singleton()->free(default_rd_samplers[i][j]);
+		}
+	}
+}

+ 125 - 102
servers/visual/rasterizer/rasterizer_storage_rd.h

@@ -3,9 +3,52 @@
 
 #include "core/rid_owner.h"
 #include "servers/visual/rasterizer/rasterizer.h"
+#include "servers/visual/rasterizer/shader_compiler_rd.h"
 #include "servers/visual/rendering_device.h"
 class RasterizerStorageRD : public RasterizerStorage {
 public:
+	enum ShaderType {
+		SHADER_TYPE_2D,
+		SHADER_TYPE_3D,
+		SHADER_TYPE_PARTICLES,
+		SHADER_TYPE_MAX
+	};
+
+	struct ShaderData {
+		virtual void set_code(const String &p_Code) = 0;
+		virtual void set_default_texture_param(const StringName &p_name, RID p_texture) = 0;
+		virtual void get_param_list(List<PropertyInfo> *p_param_list) const = 0;
+		virtual bool is_param_texture(const StringName &p_param) const = 0;
+		virtual bool is_animated() const = 0;
+		virtual bool casts_shadows() const = 0;
+		virtual Variant get_default_parameter(const StringName &p_parameter) const = 0;
+		virtual ~ShaderData() {}
+	};
+
+	typedef ShaderData *(*ShaderDataRequestFunction)();
+
+	struct MaterialData {
+
+		void update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color);
+		void update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures);
+
+		virtual void set_render_priority(int p_priority) = 0;
+		virtual void set_next_pass(RID p_pass) = 0;
+		virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) = 0;
+		virtual ~MaterialData() {}
+	};
+	typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *);
+
+	enum DefaultRDTexture {
+		DEFAULT_RD_TEXTURE_WHITE,
+		DEFAULT_RD_TEXTURE_BLACK,
+		DEFAULT_RD_TEXTURE_NORMAL,
+		DEFAULT_RD_TEXTURE_ANISO,
+		DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER,
+		DEFAULT_RD_TEXTURE_MAX
+	};
+
+private:
 	/* TEXTURE API */
 	struct Texture {
 
@@ -68,6 +111,48 @@ public:
 
 	Ref<Image> _validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format);
 
+	RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX];
+	RID default_rd_samplers[VS::CANVAS_ITEM_TEXTURE_FILTER_MAX][VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
+
+	/* SHADER */
+
+	struct Material;
+
+	struct Shader {
+		ShaderData *data;
+		String code;
+		ShaderType type;
+		Map<StringName, RID> default_texture_parameter;
+		Set<Material *> owners;
+	};
+
+	ShaderDataRequestFunction shader_data_request_func[SHADER_TYPE_MAX];
+	mutable RID_Owner<Shader> shader_owner;
+
+	/* Material */
+
+	struct Material {
+		RID self;
+		MaterialData *data;
+		Shader *shader;
+		//shortcut to shader data and type
+		ShaderType shader_type;
+		bool update_requested;
+		bool uniform_dirty;
+		bool texture_dirty;
+		Material *update_next;
+		Map<StringName, Variant> params;
+		int32_t priority;
+		RID next_pass;
+		RasterizerScene::InstanceDependency instance_dependency;
+	};
+
+	MaterialDataRequestFunction material_data_request_func[SHADER_TYPE_MAX];
+	mutable RID_Owner<Material> material_owner;
+
+	Material *material_update_list;
+	void _material_queue_update(Material *material, bool p_uniform, bool p_texture);
+	void _update_queued_materials();
 	/* RENDER TARGET */
 
 	struct RenderTarget {
@@ -164,6 +249,13 @@ public:
 		return Size2i(tex->width_2d, tex->height_2d);
 	}
 
+	_FORCE_INLINE_ RID texture_rd_get_default(DefaultRDTexture p_texture) {
+		return default_rd_textures[p_texture];
+	}
+	_FORCE_INLINE_ RID sampler_rd_get_default(VS::CanvasItemTextureFilter p_filter, VS::CanvasItemTextureRepeat p_repeat) {
+		return default_rd_samplers[p_filter][p_repeat];
+	}
+
 	/* SKY API */
 
 	struct RDSurface {
@@ -189,63 +281,44 @@ public:
 
 	/* SHADER API */
 
-	enum ShaderType {
-		SHADER_TYPE_2D,
-		SHADER_TYPE_3D,
-		SHADER_TYPE_3D_POST_PROCESS,
-		SHADER_TYPE_PARTICLES
-	};
-
-	class ShaderData {
-	public:
-		virtual void set_code(const String &p_Code) = 0;
-		virtual void set_default_texture_param(const StringName &p_name, RID p_texture) = 0;
-		virtual void get_param_list(List<PropertyInfo> *p_param_list) const = 0;
-		virtual bool is_animated() const = 0;
-		virtual bool casts_shadows() const = 0;
-		virtual Variant get_default_parameter(const StringName &p_parameter) const = 0;
-		virtual ~ShaderData() {}
-	};
-
-	typedef ShaderData *(ShaderDataRequestFunction)();
+	RID shader_create();
 
-	RID shader_create() { return RID(); }
+	void shader_set_code(RID p_shader, const String &p_code);
+	String shader_get_code(RID p_shader) const;
+	void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const;
 
-	void shader_set_code(RID p_shader, const String &p_code) {}
-	String shader_get_code(RID p_shader) const { return ""; }
-	void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const {}
-
-	void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) {}
-	RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { return RID(); }
-	Variant shader_get_param_default(RID p_material, const StringName &p_param) const { return Variant(); }
+	void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture);
+	RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const;
+	Variant shader_get_param_default(RID p_shader, const StringName &p_param) const;
+	void shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function);
 
 	/* COMMON MATERIAL API */
 
-	struct MaterialData {
+	RID material_create();
 
-		virtual void set_render_priority(int p_priority) = 0;
-		virtual void set_next_pass(RID p_pass) = 0;
-		virtual void update_parameters(const Map<StringName, Variant> &p_parameters) = 0;
-		virtual ~MaterialData() {}
-	};
-	typedef MaterialData *(MaterialDataRequestFunction)(ShaderData *);
+	void material_set_shader(RID p_material, RID p_shader);
 
-	RID material_create() { return RID(); }
+	void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value);
+	Variant material_get_param(RID p_material, const StringName &p_param) const;
 
-	void material_set_shader(RID p_shader_material, RID p_shader) {}
-	RID material_get_shader(RID p_shader_material) const { return RID(); }
+	void material_set_next_pass(RID p_material, RID p_next_material);
+	void material_set_render_priority(RID p_material, int priority);
 
-	void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) {}
-	Variant material_get_param(RID p_material, const StringName &p_param) const { return Variant(); }
+	bool material_is_animated(RID p_material);
+	bool material_casts_shadows(RID p_material);
 
-	void material_set_next_pass(RID p_material, RID p_next_material) {}
-	void material_set_render_priority(RID p_material, int priority) {}
+	void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance);
 
-	bool material_is_animated(RID p_material) { return false; }
-	bool material_casts_shadows(RID p_material) { return false; }
+	void material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function);
 
-	void material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) {}
-	void material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) {}
+	_FORCE_INLINE_ MaterialData *material_get_data(RID p_material, ShaderType p_shader_type) {
+		Material *material = material_owner.getornull(p_material);
+		if (material->shader_type != p_shader_type) {
+			return NULL;
+		} else {
+			return material->data;
+		}
+	}
 
 	/* MESH API */
 
@@ -498,11 +571,8 @@ public:
 	float reflection_probe_get_origin_max_distance(RID p_probe) const { return 0.0; }
 	bool reflection_probe_renders_shadows(RID p_probe) const { return false; }
 
-	void instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {}
-	void instance_remove_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {}
-
-	void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {}
-	void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {}
+	void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {}
+	void skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {}
 
 	/* GI PROBE API */
 
@@ -551,59 +621,14 @@ public:
 	void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) {}
 
 	/* LIGHTMAP CAPTURE */
-	struct Instantiable {
-
-		SelfList<RasterizerScene::InstanceBase>::List instance_list;
-
-		_FORCE_INLINE_ void instance_change_notify(bool p_aabb = true, bool p_materials = true) {
-
-			SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first();
-			while (instances) {
-
-				instances->self()->base_changed(p_aabb, p_materials);
-				instances = instances->next();
-			}
-		}
-
-		_FORCE_INLINE_ void instance_remove_deps() {
-			SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first();
-			while (instances) {
-
-				SelfList<RasterizerScene::InstanceBase> *next = instances->next();
-				instances->self()->base_removed();
-				instances = next;
-			}
-		}
-
-		Instantiable() {}
-		virtual ~Instantiable() {
-		}
-	};
-
-	struct LightmapCapture : public Instantiable {
-
-		PoolVector<LightmapCaptureOctree> octree;
-		AABB bounds;
-		Transform cell_xform;
-		int cell_subdiv;
-		float energy;
-		LightmapCapture() {
-			energy = 1.0;
-			cell_subdiv = 1;
-		}
-	};
 
-	mutable RID_PtrOwner<LightmapCapture> lightmap_capture_data_owner;
 	void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) {}
 	AABB lightmap_capture_get_bounds(RID p_capture) const { return AABB(); }
 	void lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) {}
 	RID lightmap_capture_create() {
-		LightmapCapture *capture = memnew(LightmapCapture);
-		return lightmap_capture_data_owner.make_rid(capture);
+		return RID();
 	}
 	PoolVector<uint8_t> lightmap_capture_get_octree(RID p_capture) const {
-		const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
-		ERR_FAIL_COND_V(!capture, PoolVector<uint8_t>());
 		return PoolVector<uint8_t>();
 	}
 	void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) {}
@@ -613,9 +638,7 @@ public:
 	void lightmap_capture_set_energy(RID p_capture, float p_energy) {}
 	float lightmap_capture_get_energy(RID p_capture) const { return 0.0; }
 	const PoolVector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const {
-		const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
-		ERR_FAIL_COND_V(!capture, NULL);
-		return &capture->octree;
+		return NULL;
 	}
 
 	/* PARTICLES */
@@ -686,7 +709,7 @@ public:
 
 	bool has_os_feature(const String &p_feature) const { return false; }
 
-	void update_dirty_resources() {}
+	void update_dirty_resources();
 
 	void set_debug_generate_wireframes(bool p_generate) {}
 
@@ -700,8 +723,8 @@ public:
 
 	static RasterizerStorage *base_singleton;
 
-	RasterizerStorageRD(){};
-	~RasterizerStorageRD() {}
+	RasterizerStorageRD();
+	~RasterizerStorageRD();
 };
 
 #endif // RASTERIZER_STORAGE_RD_H

+ 1003 - 0
servers/visual/rasterizer/shader_compiler_rd.cpp

@@ -0,0 +1,1003 @@
+#include "shader_compiler_rd.h"
+
+#include "core/os/os.h"
+#include "core/project_settings.h"
+
+#define SL ShaderLanguage
+
+static String _mktab(int p_level) {
+
+	String tb;
+	for (int i = 0; i < p_level; i++) {
+		tb += "\t";
+	}
+
+	return tb;
+}
+
+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
+	}
+	return type;
+}
+
+static int _get_datatype_size(SL::DataType p_type) {
+
+	switch (p_type) {
+
+		case SL::TYPE_VOID: return 0;
+		case SL::TYPE_BOOL: return 4;
+		case SL::TYPE_BVEC2: return 8;
+		case SL::TYPE_BVEC3: return 12;
+		case SL::TYPE_BVEC4: return 16;
+		case SL::TYPE_INT: return 4;
+		case SL::TYPE_IVEC2: return 8;
+		case SL::TYPE_IVEC3: return 12;
+		case SL::TYPE_IVEC4: return 16;
+		case SL::TYPE_UINT: return 4;
+		case SL::TYPE_UVEC2: return 8;
+		case SL::TYPE_UVEC3: return 12;
+		case SL::TYPE_UVEC4: return 16;
+		case SL::TYPE_FLOAT: return 4;
+		case SL::TYPE_VEC2: return 8;
+		case SL::TYPE_VEC3: return 12;
+		case SL::TYPE_VEC4: return 16;
+		case SL::TYPE_MAT2:
+			return 32; //4 * 4 + 4 * 4
+		case SL::TYPE_MAT3:
+			return 48; // 4 * 4 + 4 * 4 + 4 * 4
+		case SL::TYPE_MAT4: return 64;
+		case SL::TYPE_SAMPLER2D: return 16;
+		case SL::TYPE_ISAMPLER2D: return 16;
+		case SL::TYPE_USAMPLER2D: return 16;
+		case SL::TYPE_SAMPLER2DARRAY: return 16;
+		case SL::TYPE_ISAMPLER2DARRAY: return 16;
+		case SL::TYPE_USAMPLER2DARRAY: return 16;
+		case SL::TYPE_SAMPLER3D: return 16;
+		case SL::TYPE_ISAMPLER3D: return 16;
+		case SL::TYPE_USAMPLER3D: return 16;
+		case SL::TYPE_SAMPLERCUBE: return 16;
+	}
+
+	ERR_FAIL_V(0);
+}
+
+static int _get_datatype_alignment(SL::DataType p_type) {
+
+	switch (p_type) {
+
+		case SL::TYPE_VOID: return 0;
+		case SL::TYPE_BOOL: return 4;
+		case SL::TYPE_BVEC2: return 8;
+		case SL::TYPE_BVEC3: return 16;
+		case SL::TYPE_BVEC4: return 16;
+		case SL::TYPE_INT: return 4;
+		case SL::TYPE_IVEC2: return 8;
+		case SL::TYPE_IVEC3: return 16;
+		case SL::TYPE_IVEC4: return 16;
+		case SL::TYPE_UINT: return 4;
+		case SL::TYPE_UVEC2: return 8;
+		case SL::TYPE_UVEC3: return 16;
+		case SL::TYPE_UVEC4: return 16;
+		case SL::TYPE_FLOAT: return 4;
+		case SL::TYPE_VEC2: return 8;
+		case SL::TYPE_VEC3: return 16;
+		case SL::TYPE_VEC4: return 16;
+		case SL::TYPE_MAT2: return 16;
+		case SL::TYPE_MAT3: return 16;
+		case SL::TYPE_MAT4: return 16;
+		case SL::TYPE_SAMPLER2D: return 16;
+		case SL::TYPE_ISAMPLER2D: return 16;
+		case SL::TYPE_USAMPLER2D: return 16;
+		case SL::TYPE_SAMPLER2DARRAY: return 16;
+		case SL::TYPE_ISAMPLER2DARRAY: return 16;
+		case SL::TYPE_USAMPLER2DARRAY: return 16;
+		case SL::TYPE_SAMPLER3D: return 16;
+		case SL::TYPE_ISAMPLER3D: return 16;
+		case SL::TYPE_USAMPLER3D: return 16;
+		case SL::TYPE_SAMPLERCUBE: return 16;
+	}
+
+	ERR_FAIL_V(0);
+}
+static String _interpstr(SL::DataInterpolation p_interp) {
+
+	switch (p_interp) {
+		case SL::INTERPOLATION_FLAT: return "flat ";
+		case SL::INTERPOLATION_SMOOTH: return "";
+	}
+	return "";
+}
+
+static String _prestr(SL::DataPrecision p_pres) {
+
+	switch (p_pres) {
+		case SL::PRECISION_LOWP: return "lowp ";
+		case SL::PRECISION_MEDIUMP: return "mediump ";
+		case SL::PRECISION_HIGHP: return "highp ";
+		case SL::PRECISION_DEFAULT: return "";
+	}
+	return "";
+}
+
+static String _qualstr(SL::ArgumentQualifier p_qual) {
+
+	switch (p_qual) {
+		case SL::ARGUMENT_QUALIFIER_IN: return "";
+		case SL::ARGUMENT_QUALIFIER_OUT: return "out ";
+		case SL::ARGUMENT_QUALIFIER_INOUT: return "inout ";
+	}
+	return "";
+}
+
+static String _opstr(SL::Operator p_op) {
+
+	return SL::get_operator_text(p_op);
+}
+
+static String _mkid(const String &p_id) {
+
+	String id = "m_" + p_id;
+	return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl
+}
+
+static String f2sp0(float p_float) {
+
+	String num = rtoss(p_float);
+	if (num.find(".") == -1 && num.find("e") == -1) {
+		num += ".0";
+	}
+	return num;
+}
+
+static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) {
+
+	switch (p_type) {
+		case SL::TYPE_BOOL: return p_values[0].boolean ? "true" : "false";
+		case SL::TYPE_BVEC2:
+		case SL::TYPE_BVEC3:
+		case SL::TYPE_BVEC4: {
+
+			String text = "bvec" + itos(p_type - SL::TYPE_BOOL + 1) + "(";
+			for (int i = 0; i < p_values.size(); i++) {
+				if (i > 0)
+					text += ",";
+
+				text += p_values[i].boolean ? "true" : "false";
+			}
+			text += ")";
+			return text;
+		}
+
+		case SL::TYPE_INT: return itos(p_values[0].sint);
+		case SL::TYPE_IVEC2:
+		case SL::TYPE_IVEC3:
+		case SL::TYPE_IVEC4: {
+
+			String text = "ivec" + itos(p_type - SL::TYPE_INT + 1) + "(";
+			for (int i = 0; i < p_values.size(); i++) {
+				if (i > 0)
+					text += ",";
+
+				text += itos(p_values[i].sint);
+			}
+			text += ")";
+			return text;
+
+		} break;
+		case SL::TYPE_UINT: return itos(p_values[0].uint) + "u";
+		case SL::TYPE_UVEC2:
+		case SL::TYPE_UVEC3:
+		case SL::TYPE_UVEC4: {
+
+			String text = "uvec" + itos(p_type - SL::TYPE_UINT + 1) + "(";
+			for (int i = 0; i < p_values.size(); i++) {
+				if (i > 0)
+					text += ",";
+
+				text += itos(p_values[i].uint) + "u";
+			}
+			text += ")";
+			return text;
+		} break;
+		case SL::TYPE_FLOAT: return f2sp0(p_values[0].real);
+		case SL::TYPE_VEC2:
+		case SL::TYPE_VEC3:
+		case SL::TYPE_VEC4: {
+
+			String text = "vec" + itos(p_type - SL::TYPE_FLOAT + 1) + "(";
+			for (int i = 0; i < p_values.size(); i++) {
+				if (i > 0)
+					text += ",";
+
+				text += f2sp0(p_values[i].real);
+			}
+			text += ")";
+			return text;
+
+		} break;
+		case SL::TYPE_MAT2:
+		case SL::TYPE_MAT3:
+		case SL::TYPE_MAT4: {
+
+			String text = "mat" + itos(p_type - SL::TYPE_MAT2 + 2) + "(";
+			for (int i = 0; i < p_values.size(); i++) {
+				if (i > 0)
+					text += ",";
+
+				text += f2sp0(p_values[i].real);
+			}
+			text += ")";
+			return text;
+
+		} break;
+		default: ERR_FAIL_V(String());
+	}
+}
+
+String ShaderCompilerRD::_get_sampler_name(ShaderLanguage::TextureFilter p_filter, ShaderLanguage::TextureRepeat p_repeat) {
+	if (p_filter == ShaderLanguage::FILTER_DEFAULT) {
+		ERR_FAIL_COND_V(actions.default_filter == ShaderLanguage::FILTER_DEFAULT, String());
+		p_filter = actions.default_filter;
+	}
+	if (p_repeat == ShaderLanguage::REPEAT_DEFAULT) {
+		ERR_FAIL_COND_V(actions.default_repeat == ShaderLanguage::REPEAT_DEFAULT, String());
+		p_repeat = actions.default_repeat;
+	}
+	return actions.sampler_array_name + "[" + itos(p_filter + (p_repeat == ShaderLanguage::REPEAT_ENABLE ? ShaderLanguage::FILTER_DEFAULT : 0)) + "]";
+}
+
+void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, String &r_to_add, Set<StringName> &added) {
+
+	int fidx = -1;
+
+	for (int i = 0; i < p_node->functions.size(); i++) {
+		if (p_node->functions[i].name == p_for_func) {
+			fidx = i;
+			break;
+		}
+	}
+
+	ERR_FAIL_COND(fidx == -1);
+
+	for (Set<StringName>::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) {
+
+		if (added.has(E->get())) {
+			continue; //was added already
+		}
+
+		_dump_function_deps(p_node, E->get(), p_func_code, r_to_add, added);
+
+		SL::FunctionNode *fnode = NULL;
+
+		for (int i = 0; i < p_node->functions.size(); i++) {
+			if (p_node->functions[i].name == E->get()) {
+				fnode = p_node->functions[i].function;
+				break;
+			}
+		}
+
+		ERR_FAIL_COND(!fnode);
+
+		r_to_add += "\n";
+
+		String header;
+		header = _typestr(fnode->return_type) + " " + _mkid(fnode->name) + "(";
+		for (int i = 0; i < fnode->arguments.size(); i++) {
+
+			if (i > 0)
+				header += ", ";
+			header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name);
+		}
+
+		header += ")\n";
+		r_to_add += header;
+		r_to_add += p_func_code[E->get()];
+
+		added.insert(E->get());
+	}
+}
+
+String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning) {
+
+	String code;
+
+	switch (p_node->type) {
+
+		case SL::Node::TYPE_SHADER: {
+
+			SL::ShaderNode *pnode = (SL::ShaderNode *)p_node;
+
+			for (int i = 0; i < pnode->render_modes.size(); i++) {
+
+				if (p_default_actions.render_mode_defines.has(pnode->render_modes[i]) && !used_rmode_defines.has(pnode->render_modes[i])) {
+
+					r_gen_code.defines.push_back(p_default_actions.render_mode_defines[pnode->render_modes[i]]);
+					used_rmode_defines.insert(pnode->render_modes[i]);
+				}
+
+				if (p_actions.render_mode_flags.has(pnode->render_modes[i])) {
+					*p_actions.render_mode_flags[pnode->render_modes[i]] = true;
+				}
+
+				if (p_actions.render_mode_values.has(pnode->render_modes[i])) {
+					Pair<int *, int> &p = p_actions.render_mode_values[pnode->render_modes[i]];
+					*p.first = p.second;
+				}
+			}
+
+			int max_texture_uniforms = 0;
+			int max_uniforms = 0;
+
+			for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
+				if (SL::is_sampler_type(E->get().type))
+					max_texture_uniforms++;
+				else
+					max_uniforms++;
+			}
+
+			r_gen_code.texture_uniforms.resize(max_texture_uniforms);
+
+			Vector<int> uniform_sizes;
+			Vector<int> uniform_alignments;
+			Vector<StringName> uniform_defines;
+			uniform_sizes.resize(max_uniforms);
+			uniform_alignments.resize(max_uniforms);
+			uniform_defines.resize(max_uniforms);
+			bool uses_uniforms = false;
+
+			for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
+
+				String ucode;
+
+				if (SL::is_sampler_type(E->get().type)) {
+					ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + E->get().texture_order) + ") uniform ";
+				}
+
+				ucode += _prestr(E->get().precision);
+				ucode += _typestr(E->get().type);
+				ucode += " " + _mkid(E->key());
+				ucode += ";\n";
+				if (SL::is_sampler_type(E->get().type)) {
+					r_gen_code.vertex_global += ucode;
+					r_gen_code.fragment_global += ucode;
+
+					GeneratedCode::Texture texture;
+					texture.name = _mkid(E->key());
+					texture.hint = E->get().hint;
+					texture.type = E->get().type;
+					texture.filter = E->get().filter;
+					texture.repeat = E->get().repeat;
+
+					r_gen_code.texture_uniforms.write[E->get().texture_order] = texture;
+				} else {
+					if (!uses_uniforms) {
+
+						r_gen_code.defines.push_back(String("#define USE_MATERIAL_UNIFORMS\n"));
+						uses_uniforms = true;
+					}
+					uniform_defines.write[E->get().order] = ucode;
+					uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type);
+					uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type);
+				}
+
+				p_actions.uniforms->insert(E->key(), E->get());
+			}
+
+			for (int i = 0; i < max_uniforms; i++) {
+				r_gen_code.uniforms += uniform_defines[i];
+			}
+
+#if 1
+			// add up
+			int offset = 0;
+			for (int i = 0; i < uniform_sizes.size(); i++) {
+
+				int align = offset % uniform_alignments[i];
+
+				if (align != 0) {
+					offset += uniform_alignments[i] - align;
+				}
+
+				r_gen_code.uniform_offsets.push_back(offset);
+
+				offset += uniform_sizes[i];
+			}
+
+			r_gen_code.uniform_total_size = offset;
+			print_line("uniform total: " + itos(r_gen_code.uniform_total_size));
+			if (r_gen_code.uniform_total_size % 16 != 0) { //UBO sizes must be multiples of 16
+				//r_gen_code.uniform_total_size += 16 - (r_gen_code.uniform_total_size % 16);
+			}
+#else
+			// add up
+			for (int i = 0; i < uniform_sizes.size(); i++) {
+
+				if (i > 0) {
+
+					int align = uniform_sizes[i - 1] % uniform_alignments[i];
+					if (align != 0) {
+						uniform_sizes[i - 1] += uniform_alignments[i] - align;
+					}
+
+					uniform_sizes[i] = uniform_sizes[i] + uniform_sizes[i - 1];
+				}
+			}
+			//offset
+			r_gen_code.uniform_offsets.resize(uniform_sizes.size());
+			for (int i = 0; i < uniform_sizes.size(); i++) {
+
+				if (i > 0)
+					r_gen_code.uniform_offsets[i] = uniform_sizes[i - 1];
+				else
+					r_gen_code.uniform_offsets[i] = 0;
+			}
+			/*
+			for(Map<StringName,SL::ShaderNode::Uniform>::Element *E=pnode->uniforms.front();E;E=E->next()) {
+
+				if (SL::is_sampler_type(E->get().type)) {
+					continue;
+				}
+
+			}
+
+*/
+			if (uniform_sizes.size()) {
+				r_gen_code.uniform_total_size = uniform_sizes[uniform_sizes.size() - 1];
+			} else {
+				r_gen_code.uniform_total_size = 0;
+			}
+#endif
+
+			for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) {
+
+				String vcode;
+				String interp_mode = _interpstr(E->get().interpolation);
+				vcode += _prestr(E->get().precision);
+				vcode += _typestr(E->get().type);
+				vcode += " " + _mkid(E->key());
+				vcode += ";\n";
+				r_gen_code.vertex_global += interp_mode + "out " + vcode;
+				r_gen_code.fragment_global += interp_mode + "in " + vcode;
+			}
+
+			for (Map<StringName, SL::ShaderNode::Constant>::Element *E = pnode->constants.front(); E; E = E->next()) {
+				String gcode;
+				gcode += "const ";
+				gcode += _prestr(E->get().precision);
+				gcode += _typestr(E->get().type);
+				gcode += " " + _mkid(E->key());
+				gcode += "=";
+				gcode += _dump_node_code(E->get().initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+				gcode += ";\n";
+				r_gen_code.vertex_global += gcode;
+				r_gen_code.fragment_global += gcode;
+			}
+
+			Map<StringName, String> function_code;
+
+			//code for functions
+			for (int i = 0; i < pnode->functions.size(); i++) {
+				SL::FunctionNode *fnode = pnode->functions[i].function;
+				current_func_name = fnode->name;
+				function_code[fnode->name] = _dump_node_code(fnode->body, p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+			}
+
+			//place functions in actual code
+
+			Set<StringName> added_vtx;
+			Set<StringName> added_fragment; //share for light
+
+			for (int i = 0; i < pnode->functions.size(); i++) {
+
+				SL::FunctionNode *fnode = pnode->functions[i].function;
+
+				function = fnode;
+
+				current_func_name = fnode->name;
+
+				if (fnode->name == vertex_name) {
+
+					_dump_function_deps(pnode, fnode->name, function_code, r_gen_code.vertex_global, added_vtx);
+					r_gen_code.vertex = function_code[vertex_name];
+				}
+
+				if (fnode->name == fragment_name) {
+
+					_dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment);
+					r_gen_code.fragment = function_code[fragment_name];
+				}
+
+				if (fnode->name == light_name) {
+
+					_dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment);
+					r_gen_code.light = function_code[light_name];
+				}
+				function = NULL;
+			}
+
+			//code+=dump_node_code(pnode->body,p_level);
+		} break;
+		case SL::Node::TYPE_FUNCTION: {
+
+		} break;
+		case SL::Node::TYPE_BLOCK: {
+			SL::BlockNode *bnode = (SL::BlockNode *)p_node;
+
+			//variables
+			if (!bnode->single_statement) {
+				code += _mktab(p_level - 1) + "{\n";
+			}
+
+			for (int i = 0; i < bnode->statements.size(); i++) {
+
+				String scode = _dump_node_code(bnode->statements[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+
+				if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->single_statement) {
+					code += scode; //use directly
+				} else {
+					code += _mktab(p_level) + scode + ";\n";
+				}
+			}
+			if (!bnode->single_statement) {
+				code += _mktab(p_level - 1) + "}\n";
+			}
+
+		} break;
+		case SL::Node::TYPE_VARIABLE_DECLARATION: {
+			SL::VariableDeclarationNode *vdnode = (SL::VariableDeclarationNode *)p_node;
+
+			String declaration = _prestr(vdnode->precision) + _typestr(vdnode->datatype);
+			for (int i = 0; i < vdnode->declarations.size(); i++) {
+				if (i > 0) {
+					declaration += ",";
+				} else {
+					declaration += " ";
+				}
+				declaration += _mkid(vdnode->declarations[i].name);
+				if (vdnode->declarations[i].initializer) {
+					declaration += "=";
+					declaration += _dump_node_code(vdnode->declarations[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+				}
+			}
+
+			code += declaration;
+		} break;
+		case SL::Node::TYPE_VARIABLE: {
+			SL::VariableNode *vnode = (SL::VariableNode *)p_node;
+
+			if (p_assigning && p_actions.write_flag_pointers.has(vnode->name)) {
+				*p_actions.write_flag_pointers[vnode->name] = true;
+			}
+
+			if (p_default_actions.usage_defines.has(vnode->name) && !used_name_defines.has(vnode->name)) {
+				String define = p_default_actions.usage_defines[vnode->name];
+				if (define.begins_with("@")) {
+					define = p_default_actions.usage_defines[define.substr(1, define.length())];
+				}
+				r_gen_code.defines.push_back(define);
+				used_name_defines.insert(vnode->name);
+			}
+
+			if (p_actions.usage_flag_pointers.has(vnode->name) && !used_flag_pointers.has(vnode->name)) {
+				*p_actions.usage_flag_pointers[vnode->name] = true;
+				used_flag_pointers.insert(vnode->name);
+			}
+
+			if (p_default_actions.renames.has(vnode->name))
+				code = p_default_actions.renames[vnode->name];
+			else {
+				code = _mkid(vnode->name);
+				if (actions.base_uniform_string != String() && shader->uniforms.has(vnode->name) && shader->uniforms[vnode->name].texture_order < 0) {
+					code = actions.base_uniform_string + code;
+				}
+			}
+
+			if (vnode->name == time_name) {
+				if (current_func_name == vertex_name) {
+					r_gen_code.uses_vertex_time = true;
+				}
+				if (current_func_name == fragment_name || current_func_name == light_name) {
+					r_gen_code.uses_fragment_time = true;
+				}
+			}
+
+		} break;
+		case SL::Node::TYPE_CONSTANT: {
+			SL::ConstantNode *cnode = (SL::ConstantNode *)p_node;
+			return get_constant_text(cnode->datatype, cnode->values);
+
+		} break;
+		case SL::Node::TYPE_OPERATOR: {
+			SL::OperatorNode *onode = (SL::OperatorNode *)p_node;
+
+			switch (onode->op) {
+
+				case SL::OP_ASSIGN:
+				case SL::OP_ASSIGN_ADD:
+				case SL::OP_ASSIGN_SUB:
+				case SL::OP_ASSIGN_MUL:
+				case SL::OP_ASSIGN_DIV:
+				case SL::OP_ASSIGN_SHIFT_LEFT:
+				case SL::OP_ASSIGN_SHIFT_RIGHT:
+				case SL::OP_ASSIGN_MOD:
+				case SL::OP_ASSIGN_BIT_AND:
+				case SL::OP_ASSIGN_BIT_OR:
+				case SL::OP_ASSIGN_BIT_XOR:
+					code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+					break;
+				case SL::OP_BIT_INVERT:
+				case SL::OP_NEGATE:
+				case SL::OP_NOT:
+				case SL::OP_DECREMENT:
+				case SL::OP_INCREMENT:
+					code = _opstr(onode->op) + _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+					break;
+				case SL::OP_POST_DECREMENT:
+				case SL::OP_POST_INCREMENT:
+					code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + _opstr(onode->op);
+					break;
+				case SL::OP_CALL:
+				case SL::OP_CONSTRUCT: {
+
+					ERR_FAIL_COND_V(onode->arguments[0]->type != SL::Node::TYPE_VARIABLE, String());
+
+					SL::VariableNode *vnode = (SL::VariableNode *)onode->arguments[0];
+
+					bool is_texture_func = false;
+					if (onode->op == SL::OP_CONSTRUCT) {
+						code += String(vnode->name);
+					} else {
+
+						if (internal_functions.has(vnode->name)) {
+							code += vnode->name;
+							is_texture_func = texture_functions.has(vnode->name);
+						} else if (p_default_actions.renames.has(vnode->name)) {
+							code += p_default_actions.renames[vnode->name];
+						} else {
+							code += _mkid(vnode->name);
+						}
+					}
+
+					code += "(";
+
+					for (int i = 1; i < onode->arguments.size(); i++) {
+						if (i > 1)
+							code += ", ";
+						String node_code = _dump_node_code(onode->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+						if (is_texture_func && i == 1 && onode->arguments[i]->type == SL::Node::TYPE_VARIABLE) {
+
+							//need to map from texture to sampler in order to sample
+							const SL::VariableNode *varnode = static_cast<const SL::VariableNode *>(onode->arguments[i]);
+
+							StringName texture_uniform = varnode->name;
+
+							String sampler_name;
+
+							if (actions.custom_samplers.has(texture_uniform)) {
+								sampler_name = actions.custom_samplers[texture_uniform];
+							} else {
+								if (shader->uniforms.has(texture_uniform)) {
+									sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat);
+								} else {
+									bool found = false;
+
+									for (int j = 0; j < function->arguments.size(); j++) {
+										if (function->arguments[j].name == texture_uniform) {
+											if (function->arguments[j].tex_builtin_check) {
+												ERR_CONTINUE(!actions.custom_samplers.has(function->arguments[j].tex_builtin));
+												sampler_name = actions.custom_samplers[function->arguments[j].tex_builtin];
+												found = true;
+												break;
+											}
+											if (function->arguments[j].tex_argument_check) {
+												sampler_name = _get_sampler_name(function->arguments[j].tex_argument_filter, function->arguments[j].tex_argument_repeat);
+												found = true;
+												break;
+											}
+										}
+									}
+									if (!found) {
+										//function was most likely unused, so use anything (compiler will remove it anyway)
+										sampler_name = _get_sampler_name(ShaderLanguage::FILTER_DEFAULT, ShaderLanguage::REPEAT_DEFAULT);
+									}
+								}
+							}
+
+							code += ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()) + "(" + node_code + ", " + sampler_name + ")";
+						} else {
+							code += node_code;
+						}
+					}
+					code += ")";
+				} break;
+				case SL::OP_INDEX: {
+
+					code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+					code += "[";
+					code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+					code += "]";
+
+				} break;
+				case SL::OP_SELECT_IF: {
+
+					code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+					code += "?";
+					code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+					code += ":";
+					code += _dump_node_code(onode->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+
+				} break;
+
+				default: {
+
+					code = "(" + _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")";
+					break;
+				}
+			}
+
+		} break;
+		case SL::Node::TYPE_CONTROL_FLOW: {
+			SL::ControlFlowNode *cfnode = (SL::ControlFlowNode *)p_node;
+			if (cfnode->flow_op == SL::FLOW_OP_IF) {
+
+				code += _mktab(p_level) + "if (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n";
+				code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+				if (cfnode->blocks.size() == 2) {
+
+					code += _mktab(p_level) + "else\n";
+					code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+				}
+			} else if (cfnode->flow_op == SL::FLOW_OP_WHILE) {
+
+				code += _mktab(p_level) + "while (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n";
+				code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+			} else if (cfnode->flow_op == SL::FLOW_OP_FOR) {
+
+				String left = _dump_node_code(cfnode->blocks[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+				String middle = _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+				String right = _dump_node_code(cfnode->expressions[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+				code += _mktab(p_level) + "for (" + left + ";" + middle + ";" + right + ")\n";
+				code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+
+			} else if (cfnode->flow_op == SL::FLOW_OP_RETURN) {
+
+				if (cfnode->expressions.size()) {
+					code = "return " + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ";";
+				} else {
+					code = "return;";
+				}
+			} else if (cfnode->flow_op == SL::FLOW_OP_DISCARD) {
+
+				if (p_actions.usage_flag_pointers.has("DISCARD") && !used_flag_pointers.has("DISCARD")) {
+					*p_actions.usage_flag_pointers["DISCARD"] = true;
+					used_flag_pointers.insert("DISCARD");
+				}
+
+				code = "discard;";
+			} else if (cfnode->flow_op == SL::FLOW_OP_CONTINUE) {
+
+				code = "continue;";
+			} else if (cfnode->flow_op == SL::FLOW_OP_BREAK) {
+
+				code = "break;";
+			}
+
+		} break;
+		case SL::Node::TYPE_MEMBER: {
+			SL::MemberNode *mnode = (SL::MemberNode *)p_node;
+			code = _dump_node_code(mnode->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + "." + mnode->name;
+
+		} break;
+	}
+
+	return code;
+}
+
+Error ShaderCompilerRD::compile(VS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) {
+
+	Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderTypes::get_singleton()->get_types());
+
+	if (err != OK) {
+
+		Vector<String> shader = p_code.split("\n");
+		for (int i = 0; i < shader.size(); i++) {
+			print_line(itos(i + 1) + " " + shader[i]);
+		}
+
+		_err_print_error(NULL, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), ERR_HANDLER_SHADER);
+		return err;
+	}
+
+	r_gen_code.defines.clear();
+	r_gen_code.vertex = String();
+	r_gen_code.vertex_global = String();
+	r_gen_code.fragment = String();
+	r_gen_code.fragment_global = String();
+	r_gen_code.light = String();
+	r_gen_code.uses_fragment_time = false;
+	r_gen_code.uses_vertex_time = false;
+
+	used_name_defines.clear();
+	used_rmode_defines.clear();
+	used_flag_pointers.clear();
+
+	shader = parser.get_shader();
+	function = NULL;
+	_dump_node_code(shader, 1, r_gen_code, *p_actions, actions, false);
+
+	return OK;
+}
+
+void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) {
+	actions = p_actions;
+
+	vertex_name = "vertex";
+	fragment_name = "fragment";
+	light_name = "light";
+	time_name = "TIME";
+
+	List<String> func_list;
+
+	ShaderLanguage::get_builtin_funcs(&func_list);
+
+	for (List<String>::Element *E = func_list.front(); E; E = E->next()) {
+		internal_functions.insert(E->get());
+	}
+	texture_functions.insert("texture");
+	texture_functions.insert("textureProj");
+	texture_functions.insert("textureLod");
+	texture_functions.insert("textureProjLod");
+	texture_functions.insert("textureGrad");
+}
+
+ShaderCompilerRD::ShaderCompilerRD() {
+#if 0
+
+	/** SPATIAL SHADER **/
+
+	actions[VS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform";
+	actions[VS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix";
+	actions[VS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix";
+	actions[VS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix";
+	actions[VS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix";
+	actions[VS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview";
+
+	actions[VS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz";
+	actions[VS::SHADER_SPATIAL].renames["NORMAL"] = "normal";
+	actions[VS::SHADER_SPATIAL].renames["TANGENT"] = "tangent";
+	actions[VS::SHADER_SPATIAL].renames["BINORMAL"] = "binormal";
+	actions[VS::SHADER_SPATIAL].renames["POSITION"] = "position";
+	actions[VS::SHADER_SPATIAL].renames["UV"] = "uv_interp";
+	actions[VS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp";
+	actions[VS::SHADER_SPATIAL].renames["COLOR"] = "color_interp";
+	actions[VS::SHADER_SPATIAL].renames["POINT_SIZE"] = "gl_PointSize";
+	actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "gl_InstanceID";
+
+	//builtins
+
+	actions[VS::SHADER_SPATIAL].renames["TIME"] = "time";
+	actions[VS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"] = "viewport_size";
+
+	actions[VS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord";
+	actions[VS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing";
+	actions[VS::SHADER_SPATIAL].renames["NORMALMAP"] = "normalmap";
+	actions[VS::SHADER_SPATIAL].renames["NORMALMAP_DEPTH"] = "normaldepth";
+	actions[VS::SHADER_SPATIAL].renames["ALBEDO"] = "albedo";
+	actions[VS::SHADER_SPATIAL].renames["ALPHA"] = "alpha";
+	actions[VS::SHADER_SPATIAL].renames["METALLIC"] = "metallic";
+	actions[VS::SHADER_SPATIAL].renames["SPECULAR"] = "specular";
+	actions[VS::SHADER_SPATIAL].renames["ROUGHNESS"] = "roughness";
+	actions[VS::SHADER_SPATIAL].renames["RIM"] = "rim";
+	actions[VS::SHADER_SPATIAL].renames["RIM_TINT"] = "rim_tint";
+	actions[VS::SHADER_SPATIAL].renames["CLEARCOAT"] = "clearcoat";
+	actions[VS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
+	actions[VS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy";
+	actions[VS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
+	actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength";
+	actions[VS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission";
+	actions[VS::SHADER_SPATIAL].renames["AO"] = "ao";
+	actions[VS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
+	actions[VS::SHADER_SPATIAL].renames["EMISSION"] = "emission";
+	actions[VS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord";
+	actions[VS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom";
+	actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv";
+	actions[VS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture";
+	actions[VS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_buffer";
+	actions[VS::SHADER_SPATIAL].renames["DEPTH"] = "gl_FragDepth";
+	actions[VS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor";
+	actions[VS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+
+	//for light
+	actions[VS::SHADER_SPATIAL].renames["VIEW"] = "view";
+	actions[VS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color";
+	actions[VS::SHADER_SPATIAL].renames["LIGHT"] = "light";
+	actions[VS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation";
+	actions[VS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light";
+	actions[VS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light";
+
+	actions[VS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT";
+	actions[VS::SHADER_SPATIAL].usage_defines["RIM"] = "#define LIGHT_USE_RIM\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["RIM_TINT"] = "@RIM";
+	actions[VS::SHADER_SPATIAL].usage_defines["CLEARCOAT"] = "#define LIGHT_USE_CLEARCOAT\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT";
+	actions[VS::SHADER_SPATIAL].usage_defines["ANISOTROPY"] = "#define LIGHT_USE_ANISOTROPY\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
+	actions[VS::SHADER_SPATIAL].usage_defines["AO"] = "#define ENABLE_AO\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["UV"] = "#define ENABLE_UV_INTERP\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP";
+	actions[VS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
+
+	actions[VS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+
+	actions[VS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+
+	actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+	actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
+	actions[VS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
+	actions[VS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
+	actions[VS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
+
+	bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley");
+
+	if (!force_lambert) {
+		actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
+	}
+
+	actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
+	actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
+	actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
+
+	bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx");
+
+	if (!force_blinn) {
+		actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
+	} else {
+		actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n";
+	}
+
+	actions[VS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
+	actions[VS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
+	actions[VS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
+	actions[VS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
+	actions[VS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
+	actions[VS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
+	actions[VS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
+
+	/* PARTICLES SHADER */
+
+	actions[VS::SHADER_PARTICLES].renames["COLOR"] = "out_color";
+	actions[VS::SHADER_PARTICLES].renames["VELOCITY"] = "out_velocity_active.xyz";
+	actions[VS::SHADER_PARTICLES].renames["MASS"] = "mass";
+	actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "shader_active";
+	actions[VS::SHADER_PARTICLES].renames["RESTART"] = "restart";
+	actions[VS::SHADER_PARTICLES].renames["CUSTOM"] = "out_custom";
+	actions[VS::SHADER_PARTICLES].renames["TRANSFORM"] = "xform";
+	actions[VS::SHADER_PARTICLES].renames["TIME"] = "time";
+	actions[VS::SHADER_PARTICLES].renames["LIFETIME"] = "lifetime";
+	actions[VS::SHADER_PARTICLES].renames["DELTA"] = "local_delta";
+	actions[VS::SHADER_PARTICLES].renames["NUMBER"] = "particle_number";
+	actions[VS::SHADER_PARTICLES].renames["INDEX"] = "index";
+	actions[VS::SHADER_PARTICLES].renames["GRAVITY"] = "current_gravity";
+	actions[VS::SHADER_PARTICLES].renames["EMISSION_TRANSFORM"] = "emission_transform";
+	actions[VS::SHADER_PARTICLES].renames["RANDOM_SEED"] = "random_seed";
+
+	actions[VS::SHADER_PARTICLES].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n";
+	actions[VS::SHADER_PARTICLES].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n";
+	actions[VS::SHADER_PARTICLES].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n";
+#endif
+}

+ 92 - 0
servers/visual/rasterizer/shader_compiler_rd.h

@@ -0,0 +1,92 @@
+#ifndef SHADER_COMPILER_RD_H
+#define SHADER_COMPILER_RD_H
+
+#include "core/pair.h"
+#include "servers/visual/shader_language.h"
+#include "servers/visual/shader_types.h"
+#include "servers/visual_server.h"
+
+class ShaderCompilerRD {
+public:
+	struct IdentifierActions {
+
+		Map<StringName, Pair<int *, int> > render_mode_values;
+		Map<StringName, bool *> render_mode_flags;
+		Map<StringName, bool *> usage_flag_pointers;
+		Map<StringName, bool *> write_flag_pointers;
+
+		Map<StringName, ShaderLanguage::ShaderNode::Uniform> *uniforms;
+	};
+
+	struct GeneratedCode {
+
+		Vector<String> defines;
+		struct Texture {
+			StringName name;
+			ShaderLanguage::DataType type;
+			ShaderLanguage::ShaderNode::Uniform::Hint hint;
+			ShaderLanguage::TextureFilter filter;
+			ShaderLanguage::TextureRepeat repeat;
+		};
+
+		Vector<Texture> texture_uniforms;
+
+		Vector<uint32_t> uniform_offsets;
+		uint32_t uniform_total_size;
+		String uniforms;
+		String vertex_global;
+		String vertex;
+		String fragment_global;
+		String fragment;
+		String light;
+
+		bool uses_fragment_time;
+		bool uses_vertex_time;
+	};
+
+	struct DefaultIdentifierActions {
+
+		Map<StringName, String> renames;
+		Map<StringName, String> render_mode_defines;
+		Map<StringName, String> usage_defines;
+		Map<StringName, String> custom_samplers;
+		ShaderLanguage::TextureFilter default_filter;
+		ShaderLanguage::TextureRepeat default_repeat;
+		String sampler_array_name;
+		int base_texture_binding_index;
+		int texture_layout_set;
+		String base_uniform_string;
+	};
+
+private:
+	ShaderLanguage parser;
+
+	String _get_sampler_name(ShaderLanguage::TextureFilter p_filter, ShaderLanguage::TextureRepeat p_repeat);
+
+	void _dump_function_deps(const ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, String &r_to_add, Set<StringName> &added);
+	String _dump_node_code(const ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning);
+
+	const ShaderLanguage::ShaderNode *shader;
+	const ShaderLanguage::FunctionNode *function;
+	StringName current_func_name;
+	StringName vertex_name;
+	StringName fragment_name;
+	StringName light_name;
+	StringName time_name;
+	Set<StringName> texture_functions;
+
+	Set<StringName> used_name_defines;
+	Set<StringName> used_flag_pointers;
+	Set<StringName> used_rmode_defines;
+	Set<StringName> internal_functions;
+
+	DefaultIdentifierActions actions;
+
+public:
+	Error compile(VS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code);
+
+	void initialize(DefaultIdentifierActions p_actions);
+	ShaderCompilerRD();
+};
+
+#endif // SHADERCOMPILERRD_H

+ 7 - 1
servers/visual/rasterizer/shader_rd.cpp

@@ -243,7 +243,11 @@ void ShaderRD::_compile_version(Version *p_version) {
 			RD::ShaderStageSource stage;
 			stage.shader_source = builder.as_string();
 			stage.shader_stage = RD::SHADER_STAGE_FRAGMENT;
-
+#if 0
+			if (stage.shader_stage == RD::SHADER_STAGE_FRAGMENT && p_version->uniforms.length()) {
+				print_line(stage.shader_source.get_with_code_lines());
+			}
+#endif
 			stages.push_back(stage);
 		}
 
@@ -285,6 +289,8 @@ void ShaderRD::version_set_code(RID p_version, const String &p_uniforms, const S
 	version->fragment_light = p_fragment_light.utf8();
 	version->fragment_globals = p_fragment_globals.utf8();
 	version->fragment_code = p_fragment_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());

+ 46 - 14
servers/visual/rasterizer/shaders/canvas.glsl

@@ -31,10 +31,13 @@ layout(location=3) out vec2 pixel_size_interp;
 
 #endif
 
+#ifdef USE_MATERIAL_UNIFORMS
+layout(set = 1, binding = 1, std140) uniform MaterialUniforms {
 /* clang-format off */
 MATERIAL_UNIFORMS
 /* clang-format on */
-
+} material;
+#endif
 
 /* clang-format off */
 VERTEX_SHADER_GLOBALS
@@ -207,6 +210,7 @@ VERTEX_SHADER_CODE
 #endif
 #endif
 
+
 	vertex = (canvas_data.canvas_transform * vec4(vertex,0.0,1.0)).xy;
 
 	vertex_interp = vertex;
@@ -243,33 +247,41 @@ layout(location=3) in vec2 pixel_size_interp;
 
 layout(location = 0) out vec4 frag_color;
 
+#ifdef USE_MATERIAL_UNIFORMS
+layout(set = 1, binding = 1, std140) uniform MaterialUniforms {
 /* clang-format off */
 MATERIAL_UNIFORMS
 /* clang-format on */
+} material;
+#endif
 
 
 /* clang-format off */
 FRAGMENT_SHADER_GLOBALS
 /* clang-format on */
 
+#ifdef LIGHT_SHADER_CODE_USED
 
-void light_compute(
-		inout vec4 light,
-		inout vec2 light_vec,
-		inout float light_height,
-		inout vec4 light_color,
-		vec2 light_uv,
-		inout vec4 shadow_color,
+vec4 light_compute(
+		vec3 light_vertex,
+		vec3 light_position,
 		vec3 normal,
-		vec2 uv,
+		vec4 light_color,
+		float light_energy,
+		vec4 specular_shininess,
+		inout vec4 shadow_modulate,
 		vec2 screen_uv,
+		vec2 uv,
 		vec4 color) {
 
+	vec4 light = vec4(0.0);
 	/* clang-format off */
 LIGHT_SHADER_CODE
 	/* clang-format on */
+	return light;
 }
 
+#endif
 
 #ifdef USE_NINEPATCH
 
@@ -391,8 +403,13 @@ void main() {
 
 #if defined(SCREEN_UV_USED)
 	vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size;
+#else
+	vec2 screen_uv = vec2(0.0);
 #endif
 
+	vec3 light_vertex = vec3(vertex,0.0);
+	vec2 shadow_vertex = vertex;
+
 	{
 		float normal_depth = 1.0;
 
@@ -449,14 +466,25 @@ FRAGMENT_SHADER_CODE
 		light_base&=0xFF;
 
 		vec2 tex_uv = (vec4(vertex,0.0,1.0) * mat4(light_array.data[light_base].matrix[0],light_array.data[light_base].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 light_color = texture(sampler2D(light_textures[i],texture_sampler),tex_uv);
+		vec4 light_color = texture(sampler2D(light_textures[i],texture_sampler),tex_uv);				
 		vec4 light_base_color = light_array.data[light_base].color;
+
+#ifdef LIGHT_SHADER_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,color,uv);
+#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 = vec3(vertex,0.0);
+			vec3 pos = light_vertex;
 			vec3 light_vec = normalize(light_pos-pos);
 			float cNdotL = max(0.0,dot(normal,light_vec));
 
@@ -480,7 +508,7 @@ FRAGMENT_SHADER_CODE
 			}
 
 		}
-
+#endif
 		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
 			light_color.a = 0.0;
@@ -488,7 +516,7 @@ FRAGMENT_SHADER_CODE
 
 		if (bool(light_array.data[light_base].flags&LIGHT_FLAGS_HAS_SHADOW)) {
 
-			vec2 shadow_pos = (vec4(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 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);
@@ -550,7 +578,11 @@ FRAGMENT_SHADER_CODE
 				shadow/=13.0;
 			}
 
-			light_color = mix(light_color,light_array.data[light_base].shadow_color,shadow);
+			vec4 shadow_color = light_array.data[light_base].shadow_color;
+#ifdef LIGHT_SHADER_CODE_USED
+			shadow_color*=shadow_modulate;
+#endif
+			light_color = mix(light_color,shadow_color,shadow);
 
 		}
 

+ 22 - 9
servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl

@@ -59,9 +59,14 @@ layout(set = 0, binding = 5) uniform textureBuffer instancing_buffer;
 
 /* SET1: Is reserved for the material */
 
-//
 
-/* SET2: Canvas Item State */
+#ifdef USE_MATERIAL_SAMPLERS
+
+layout(set = 1, binding = 0) uniform sampler material_samplers[12];
+
+#endif
+
+/* SET2: Canvas Item State (including lighting) */
 
 
 layout(set = 2, binding = 0, std140) uniform CanvasData {
@@ -69,6 +74,9 @@ layout(set = 2, binding = 0, std140) uniform CanvasData {
 	mat4 screen_transform;
 	mat4 canvas_normal_transform;
 	vec4 canvas_modulation;
+	vec2 screen_pixel_size;
+	float time;
+	float time_pad;
 	//uint light_count;
 } canvas_data;
 
@@ -80,9 +88,6 @@ layout(set = 2, binding = 2, std140) uniform SkeletonData {
 } skeleton_data;
 
 
-
-/* SET3: Lighting */
-
 #ifdef USE_LIGHTING
 
 #define LIGHT_FLAGS_BLEND_MASK (3<<16)
@@ -112,13 +117,21 @@ struct Light {
 	float pad2;
 };
 
-layout(set = 3, binding = 0, std140) uniform LightData {
+layout(set = 2, binding = 3, std140) uniform LightData {
 	Light data[MAX_LIGHTS];
 } light_array;
 
-layout(set = 3, binding = 1) uniform texture2D light_textures[MAX_LIGHT_TEXTURES];
-layout(set = 3, binding = 2) uniform texture2D shadow_textures[MAX_LIGHT_TEXTURES];
+layout(set = 2, binding = 4) uniform texture2D light_textures[MAX_LIGHT_TEXTURES];
+layout(set = 2, binding = 5) uniform texture2D shadow_textures[MAX_LIGHT_TEXTURES];
+
+layout(set = 2, binding = 6) uniform sampler shadow_sampler;
+
+#endif
+
+/* SET3: Render Target Data */
+
+#ifdef SCREEN_TEXTURE_USED
 
-layout(set = 3, binding = 3) uniform sampler shadow_sampler;
+layout(set = 3, binding = 1) uniform texture2D screen_texture;
 
 #endif

+ 303 - 2
servers/visual/shader_language.cpp

@@ -207,6 +207,14 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
 	"HINT_BLACK_ALBEDO_TEXTURE",
 	"HINT_COLOR",
 	"HINT_RANGE",
+	"FILTER_NEAREST",
+	"FILTER_LINEAR",
+	"FILTER_NEAREST_MIPMAP",
+	"FILTER_LINEAR_MIPMAP",
+	"FILTER_NEAREST_MIPMAP_ANISO",
+	"FILTER_LINEAR_MIPMAP_ANISO",
+	"REPEAT_ENABLE",
+	"REPEAT_DISABLE",
 	"SHADER_TYPE",
 	"CURSOR",
 	"ERROR",
@@ -304,8 +312,15 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
 	{ TK_HINT_BLACK_ALBEDO_TEXTURE, "hint_black_albedo" },
 	{ TK_HINT_COLOR, "hint_color" },
 	{ TK_HINT_RANGE, "hint_range" },
+	{ TK_FILTER_NEAREST, "filter_nearest" },
+	{ TK_FILTER_LINEAR, "filter_linear" },
+	{ TK_FILTER_NEAREST_MIPMAP, "filter_nearest_mipmap" },
+	{ TK_FILTER_LINEAR_MIPMAP, "filter_linear_mipmap" },
+	{ TK_FILTER_NEAREST_MIPMAP_ANISO, "filter_nearest_mipmap_aniso" },
+	{ TK_FILTER_LINEAR_MIPMAP_ANISO, "filter_linear_mipmap_aniso" },
+	{ TK_REPEAT_ENABLE, "repeat_enable" },
+	{ TK_REPEAT_DISABLE, "repeat_disable" },
 	{ TK_SHADER_TYPE, "shader_type" },
-
 	{ TK_ERROR, NULL }
 };
 
@@ -2558,6 +2573,132 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
 	return Variant();
 }
 
+PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform &p_uniform) {
+	PropertyInfo pi;
+	switch (p_uniform.type) {
+		case ShaderLanguage::TYPE_VOID: pi.type = Variant::NIL; break;
+		case ShaderLanguage::TYPE_BOOL: pi.type = Variant::BOOL; break;
+		case ShaderLanguage::TYPE_BVEC2:
+			pi.type = Variant::INT;
+			pi.hint = PROPERTY_HINT_FLAGS;
+			pi.hint_string = "x,y";
+			break;
+		case ShaderLanguage::TYPE_BVEC3:
+			pi.type = Variant::INT;
+			pi.hint = PROPERTY_HINT_FLAGS;
+			pi.hint_string = "x,y,z";
+			break;
+		case ShaderLanguage::TYPE_BVEC4:
+			pi.type = Variant::INT;
+			pi.hint = PROPERTY_HINT_FLAGS;
+			pi.hint_string = "x,y,z,w";
+			break;
+		case ShaderLanguage::TYPE_UINT:
+		case ShaderLanguage::TYPE_INT: {
+			pi.type = Variant::INT;
+			if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
+				pi.hint = PROPERTY_HINT_RANGE;
+				pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]);
+			}
+
+		} break;
+		case ShaderLanguage::TYPE_IVEC2:
+		case ShaderLanguage::TYPE_IVEC3:
+		case ShaderLanguage::TYPE_IVEC4:
+		case ShaderLanguage::TYPE_UVEC2:
+		case ShaderLanguage::TYPE_UVEC3:
+		case ShaderLanguage::TYPE_UVEC4: {
+
+			pi.type = Variant::POOL_INT_ARRAY;
+		} break;
+		case ShaderLanguage::TYPE_FLOAT: {
+			pi.type = Variant::REAL;
+			if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
+				pi.hint = PROPERTY_HINT_RANGE;
+				pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]);
+			}
+
+		} break;
+		case ShaderLanguage::TYPE_VEC2: pi.type = Variant::VECTOR2; break;
+		case ShaderLanguage::TYPE_VEC3: pi.type = Variant::VECTOR3; break;
+		case ShaderLanguage::TYPE_VEC4: {
+			if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+				pi.type = Variant::COLOR;
+			} else {
+				pi.type = Variant::PLANE;
+			}
+		} break;
+		case ShaderLanguage::TYPE_MAT2: pi.type = Variant::TRANSFORM2D; break;
+		case ShaderLanguage::TYPE_MAT3: pi.type = Variant::BASIS; break;
+		case ShaderLanguage::TYPE_MAT4: pi.type = Variant::TRANSFORM; break;
+		case ShaderLanguage::TYPE_SAMPLER2D:
+		case ShaderLanguage::TYPE_ISAMPLER2D:
+		case ShaderLanguage::TYPE_USAMPLER2D: {
+
+			pi.type = Variant::OBJECT;
+			pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+			pi.hint_string = "Texture2D";
+		} break;
+		case ShaderLanguage::TYPE_SAMPLER2DARRAY:
+		case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
+		case ShaderLanguage::TYPE_USAMPLER2DARRAY: {
+
+			pi.type = Variant::OBJECT;
+			pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+			pi.hint_string = "TextureArray";
+		} break;
+		case ShaderLanguage::TYPE_SAMPLER3D:
+		case ShaderLanguage::TYPE_ISAMPLER3D:
+		case ShaderLanguage::TYPE_USAMPLER3D: {
+			pi.type = Variant::OBJECT;
+			pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+			pi.hint_string = "Texture3D";
+		} break;
+		case ShaderLanguage::TYPE_SAMPLERCUBE: {
+
+			pi.type = Variant::OBJECT;
+			pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+			pi.hint_string = "CubeMap";
+		} break;
+	}
+	return pi;
+}
+
+uint32_t ShaderLanguage::get_type_size(DataType p_type) {
+	switch (p_type) {
+		case TYPE_BOOL:
+		case TYPE_INT:
+		case TYPE_UINT:
+		case TYPE_FLOAT: return 4;
+		case TYPE_BVEC2:
+		case TYPE_IVEC2:
+		case TYPE_UVEC2:
+		case TYPE_VEC2: return 8;
+		case TYPE_BVEC3:
+		case TYPE_IVEC3:
+		case TYPE_UVEC3:
+		case TYPE_VEC3: return 12;
+		case TYPE_BVEC4:
+		case TYPE_IVEC4:
+		case TYPE_UVEC4:
+		case TYPE_VEC4: return 16;
+		case TYPE_MAT2: return 8;
+		case TYPE_MAT3: return 12;
+		case TYPE_MAT4: return 16;
+		case TYPE_SAMPLER2D:
+		case TYPE_ISAMPLER2D:
+		case TYPE_USAMPLER2D:
+		case TYPE_SAMPLER2DARRAY:
+		case TYPE_ISAMPLER2DARRAY:
+		case TYPE_USAMPLER2DARRAY:
+		case TYPE_SAMPLER3D:
+		case TYPE_ISAMPLER3D:
+		case TYPE_USAMPLER3D:
+		case TYPE_SAMPLERCUBE: return 4; //not really, but useful for indices
+	}
+	return 0;
+}
+
 void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
 
 	Set<String> kws;
@@ -2795,6 +2936,78 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
 	return false;
 }
 
+bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) {
+	for (int i = 0; shader->functions.size(); i++) {
+		if (shader->functions[i].name == p_name) {
+
+			ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false);
+			FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument];
+			if (arg->tex_builtin_check) {
+				_set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other).");
+				return false;
+			} else if (arg->tex_argument_check) {
+				//was checked, verify that filter and repeat are the same
+				if (arg->tex_argument_filter == p_filter && arg->tex_argument_repeat == p_repeat) {
+					return true;
+				} else {
+
+					_set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using textures that differ in either filter or repeat setting.");
+					return false;
+				}
+			} else {
+
+				arg->tex_argument_check = true;
+				arg->tex_argument_filter = p_filter;
+				arg->tex_argument_repeat = p_repeat;
+				for (Map<StringName, Set<int> >::Element *E = arg->tex_argument_connect.front(); E; E = E->next()) {
+					for (Set<int>::Element *F = E->get().front(); F; F = F->next()) {
+						if (!_propagate_function_call_sampler_uniform_settings(E->key(), F->get(), p_filter, p_repeat)) {
+							return false;
+						}
+					}
+				}
+				return true;
+			}
+		}
+	}
+	ERR_FAIL_V(false); //bug? function not found
+}
+bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin) {
+	for (int i = 0; shader->functions.size(); i++) {
+		if (shader->functions[i].name == p_name) {
+
+			ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false);
+			FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument];
+			if (arg->tex_argument_check) {
+				_set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other).");
+				return false;
+			} else if (arg->tex_builtin_check) {
+				//was checked, verify that the built-in is the same
+				if (arg->tex_builtin == p_builtin) {
+					return true;
+				} else {
+					_set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using different built-ins. Only calling with the same built-in is supported.");
+					return false;
+				}
+			} else {
+
+				arg->tex_builtin_check = true;
+				arg->tex_builtin = p_builtin;
+
+				for (Map<StringName, Set<int> >::Element *E = arg->tex_argument_connect.front(); E; E = E->next()) {
+					for (Set<int>::Element *F = E->get().front(); F; F = F->next()) {
+						if (!_propagate_function_call_sampler_builtin_reference(E->key(), F->get(), p_builtin)) {
+							return false;
+						}
+					}
+				}
+				return true;
+			}
+		}
+	}
+	ERR_FAIL_V(false); //bug? function not found
+}
+
 ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) {
 
 	Vector<Expression> expression;
@@ -2944,6 +3157,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 				}
 
 				//test if function was parsed first
+				int function_index = -1;
 				for (int i = 0; i < shader->functions.size(); i++) {
 					if (shader->functions[i].name == name) {
 						//add to current function as dependency
@@ -2953,6 +3167,9 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 								break;
 							}
 						}
+
+						//see if texture arguments must connect
+						function_index = i;
 						break;
 					}
 				}
@@ -2974,6 +3191,71 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 				}
 				completion_class = TAG_GLOBAL; // reset sub-class
 
+				if (function_index >= 0) {
+					//connect texture arguments, so we can cache in the
+					//argument what type of filter and repeat to use
+
+					FunctionNode *call_function = shader->functions[function_index].function;
+					if (call_function) {
+
+						//get current base function
+						FunctionNode *base_function = NULL;
+						{
+							BlockNode *b = p_block;
+
+							while (b) {
+
+								if (b->parent_function) {
+									base_function = b->parent_function;
+									break;
+								} else {
+									b = b->parent_block;
+								}
+							}
+						}
+
+						ERR_FAIL_COND_V(!base_function, NULL); //bug, wtf
+
+						for (int i = 0; i < call_function->arguments.size(); i++) {
+							int argidx = i + 1;
+							if (argidx < func->arguments.size() && is_sampler_type(call_function->arguments[i].type)) {
+								//let's see where our argument comes from
+								Node *n = func->arguments[argidx];
+								ERR_CONTINUE(n->type != Node::TYPE_VARIABLE); //bug? this should always be a variable
+								VariableNode *vn = static_cast<VariableNode *>(n);
+								StringName varname = vn->name;
+								if (shader->uniforms.has(varname)) {
+									//being sampler, this either comes from a uniform
+									ShaderNode::Uniform *u = &shader->uniforms[varname];
+									ERR_CONTINUE(u->type != call_function->arguments[i].type); //this should have been validated previously
+									//propagate
+									if (!_propagate_function_call_sampler_uniform_settings(name, i, u->filter, u->repeat)) {
+										return NULL;
+									}
+								} else if (p_builtin_types.has(varname)) {
+									//a built-in
+									if (!_propagate_function_call_sampler_builtin_reference(name, i, varname)) {
+										return NULL;
+									}
+								} else {
+									//or this comes from an argument, but nothing else can be a sampler
+									bool found = false;
+									for (int j = 0; j < base_function->arguments.size(); j++) {
+										if (base_function->arguments[j].name == varname) {
+											if (!base_function->arguments[j].tex_argument_connect.has(call_function->name)) {
+												base_function->arguments.write[j].tex_argument_connect[call_function->name] = Set<int>();
+											}
+											base_function->arguments.write[j].tex_argument_connect[call_function->name].insert(i);
+											found = true;
+											break;
+										}
+									}
+									ERR_CONTINUE(!found);
+								}
+							}
+						}
+					}
+				}
 				expr = func;
 
 			} else {
@@ -4980,7 +5262,22 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 								_set_error("Expected ','");
 								return ERR_PARSE_ERROR;
 							}
-
+						} else if (tk.type == TK_FILTER_LINEAR) {
+							uniform2.filter = FILTER_LINEAR;
+						} else if (tk.type == TK_FILTER_NEAREST) {
+							uniform2.filter = FILTER_NEAREST;
+						} else if (tk.type == TK_FILTER_NEAREST_MIPMAP) {
+							uniform2.filter = FILTER_NEAREST_MIPMAP;
+						} else if (tk.type == TK_FILTER_LINEAR_MIPMAP) {
+							uniform2.filter = FILTER_LINEAR_MIPMAP;
+						} else if (tk.type == TK_FILTER_NEAREST_MIPMAP_ANISO) {
+							uniform2.filter = FILTER_NEAREST_MIPMAP_ANISO;
+						} else if (tk.type == TK_FILTER_LINEAR_MIPMAP_ANISO) {
+							uniform2.filter = FILTER_LINEAR_MIPMAP_ANISO;
+						} else if (tk.type == TK_REPEAT_DISABLE) {
+							uniform2.repeat = REPEAT_DISABLE;
+						} else if (tk.type == TK_REPEAT_ENABLE) {
+							uniform2.repeat = REPEAT_ENABLE;
 						} else {
 							_set_error("Expected valid type hint after ':'.");
 						}
@@ -5293,6 +5590,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 					arg.name = pname;
 					arg.precision = pprecision;
 					arg.qualifier = qualifier;
+					arg.tex_argument_check = false;
+					arg.tex_builtin_check = false;
+					arg.tex_argument_filter = FILTER_DEFAULT;
+					arg.tex_argument_repeat = REPEAT_DEFAULT;
 
 					func_node->arguments.push_back(arg);
 

+ 42 - 1
servers/visual/shader_language.h

@@ -155,6 +155,14 @@ public:
 		TK_HINT_BLACK_ALBEDO_TEXTURE,
 		TK_HINT_COLOR,
 		TK_HINT_RANGE,
+		TK_FILTER_NEAREST,
+		TK_FILTER_LINEAR,
+		TK_FILTER_NEAREST_MIPMAP,
+		TK_FILTER_LINEAR_MIPMAP,
+		TK_FILTER_NEAREST_MIPMAP_ANISO,
+		TK_FILTER_LINEAR_MIPMAP_ANISO,
+		TK_REPEAT_ENABLE,
+		TK_REPEAT_DISABLE,
 		TK_SHADER_TYPE,
 		TK_CURSOR,
 		TK_ERROR,
@@ -284,6 +292,22 @@ public:
 		TAG_ARRAY,
 	};
 
+	enum TextureFilter {
+		FILTER_NEAREST,
+		FILTER_LINEAR,
+		FILTER_NEAREST_MIPMAP,
+		FILTER_LINEAR_MIPMAP,
+		FILTER_NEAREST_MIPMAP_ANISO,
+		FILTER_LINEAR_MIPMAP_ANISO,
+		FILTER_DEFAULT,
+	};
+
+	enum TextureRepeat {
+		REPEAT_DISABLE,
+		REPEAT_ENABLE,
+		REPEAT_DEFAULT,
+	};
+
 	struct Node {
 		Node *next;
 
@@ -485,11 +509,20 @@ public:
 	};
 
 	struct FunctionNode : public Node {
+
 		struct Argument {
 			ArgumentQualifier qualifier;
 			StringName name;
 			DataType type;
 			DataPrecision precision;
+			//for passing textures as arguments
+			bool tex_argument_check;
+			TextureFilter tex_argument_filter;
+			TextureRepeat tex_argument_repeat;
+			bool tex_builtin_check;
+			StringName tex_builtin;
+
+			Map<StringName, Set<int> > tex_argument_connect;
 		};
 
 		StringName name;
@@ -555,6 +588,8 @@ public:
 			DataPrecision precision;
 			Vector<ConstantNode::Value> default_value;
 			Hint hint;
+			TextureFilter filter;
+			TextureRepeat repeat;
 			float hint_range[3];
 
 			Uniform() :
@@ -562,7 +597,9 @@ public:
 					texture_order(0),
 					type(TYPE_VOID),
 					precision(PRECISION_DEFAULT),
-					hint(HINT_NONE) {
+					hint(HINT_NONE),
+					filter(FILTER_DEFAULT),
+					repeat(REPEAT_DEFAULT) {
 				hint_range[0] = 0.0f;
 				hint_range[1] = 1.0f;
 				hint_range[2] = 0.001f;
@@ -631,6 +668,8 @@ public:
 	static bool is_scalar_type(DataType p_type);
 	static bool is_sampler_type(DataType p_type);
 	static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
+	static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform);
+	static uint32_t get_type_size(DataType p_type);
 
 	static void get_keyword_list(List<String> *r_keywords);
 	static void get_builtin_funcs(List<String> *r_keywords);
@@ -750,6 +789,8 @@ private:
 
 	bool _validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type);
 	bool _parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg = NULL);
+	bool _propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat);
+	bool _propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin);
 
 	Node *_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types);
 	ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node);

+ 15 - 11
servers/visual/shader_types.cpp

@@ -202,14 +202,17 @@ ShaderTypes::ShaderTypes() {
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["POINT_SIZE"] = ShaderLanguage::TYPE_FLOAT;
 
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
-	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
-	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["EXTRA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["CANVAS_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["SCREEN_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].can_discard = false;
 
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC2;
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SHADOW_VERTEX"] = ShaderLanguage::TYPE_VEC2;
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["LIGHT_VERTEX"] = ShaderLanguage::TYPE_VEC3;
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3;
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMALMAP"] = ShaderLanguage::TYPE_VEC3;
@@ -219,6 +222,8 @@ ShaderTypes::ShaderTypes() {
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SPECULAR_SHININESS_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SPECULAR_SHININESS"] = constt(ShaderLanguage::TYPE_VEC4);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
@@ -229,18 +234,17 @@ ShaderTypes::ShaderTypes() {
 
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
-	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2);
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SPECULAR_SHININESS"] = constt(ShaderLanguage::TYPE_VEC4);
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_POSITION"] = constt(ShaderLanguage::TYPE_VEC3);
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_VERTEX"] = constt(ShaderLanguage::TYPE_VEC3);
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT"] = ShaderLanguage::TYPE_VEC4;
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SHADOW_MODULATE"] = ShaderLanguage::TYPE_VEC4;
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
-	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
-	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_VEC"] = ShaderLanguage::TYPE_VEC2;
-	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SHADOW_VEC"] = ShaderLanguage::TYPE_VEC2;
-	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_HEIGHT"] = ShaderLanguage::TYPE_FLOAT;
-	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_COLOR"] = ShaderLanguage::TYPE_VEC4;
-	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_UV"] = constt(ShaderLanguage::TYPE_VEC2);
-	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT"] = ShaderLanguage::TYPE_VEC4;
-	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SHADOW_COLOR"] = ShaderLanguage::TYPE_VEC4;
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].can_discard = true;

+ 0 - 1
servers/visual/visual_server_raster.h

@@ -209,7 +209,6 @@ public:
 	BIND0R(RID, material_create)
 
 	BIND2(material_set_shader, RID, RID)
-	BIND1RC(RID, material_get_shader, RID)
 
 	BIND3(material_set_param, RID, const StringName &, const Variant &)
 	BIND2RC(Variant, material_get_param, RID, const StringName &)

+ 45 - 48
servers/visual/visual_server_scene.cpp

@@ -304,12 +304,12 @@ void VisualServerScene::scenario_set_reflection_atlas_size(RID p_scenario, int p
 
 /* INSTANCING API */
 
-void VisualServerScene::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_materials) {
+void VisualServerScene::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) {
 
 	if (p_update_aabb)
 		p_instance->update_aabb = true;
-	if (p_update_materials)
-		p_instance->update_materials = true;
+	if (p_update_dependencies)
+		p_instance->update_dependencies = true;
 
 	if (p_instance->update_item.in_list())
 		return;
@@ -338,8 +338,6 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
 	if (instance->base_type != VS::INSTANCE_NONE) {
 		//free anything related to that base
 
-		VSG::storage->instance_remove_dependency(instance->base, instance);
-
 		if (instance->base_type == VS::INSTANCE_GI_PROBE) {
 			//if gi probe is baking, wait until done baking, else race condition may happen when removing it
 			//from octree
@@ -421,12 +419,6 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
 		}
 
 		instance->blend_values.clear();
-
-		for (int i = 0; i < instance->materials.size(); i++) {
-			if (instance->materials[i].is_valid()) {
-				VSG::storage->material_remove_instance_owner(instance->materials[i], instance);
-			}
-		}
 		instance->materials.clear();
 	}
 
@@ -493,13 +485,13 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
 			}
 		}
 
-		VSG::storage->instance_add_dependency(p_base, instance);
-
 		instance->base = p_base;
 
-		if (scenario)
-			_instance_queue_update(instance, true, true);
+		//forcefully update the dependency now, so if for some reason it gets removed, we can immediately clear it
+		VSG::storage->base_update_dependency(p_base, instance);
 	}
+
+	_instance_queue_update(instance, true, true);
 }
 void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario) {
 
@@ -635,21 +627,15 @@ void VisualServerScene::instance_set_surface_material(RID p_instance, int p_surf
 	ERR_FAIL_COND(!instance);
 
 	if (instance->base_type == VS::INSTANCE_MESH) {
-		//may not have been updated yet
-		instance->materials.resize(VSG::storage->mesh_get_surface_count(instance->base));
+		//may not have been updated yet, may also have not been set yet. When updated will be correcte, worst case
+		instance->materials.resize(MAX(p_surface + 1, VSG::storage->mesh_get_surface_count(instance->base)));
 	}
 
 	ERR_FAIL_INDEX(p_surface, instance->materials.size());
 
-	if (instance->materials[p_surface].is_valid()) {
-		VSG::storage->material_remove_instance_owner(instance->materials[p_surface], instance);
-	}
 	instance->materials.write[p_surface] = p_material;
-	instance->base_changed(false, true);
 
-	if (instance->materials[p_surface].is_valid()) {
-		VSG::storage->material_add_instance_owner(instance->materials[p_surface], instance);
-	}
+	_instance_queue_update(instance, false, true);
 }
 
 void VisualServerScene::instance_set_visible(RID p_instance, bool p_visible) {
@@ -753,17 +739,13 @@ void VisualServerScene::instance_attach_skeleton(RID p_instance, RID p_skeleton)
 	if (instance->skeleton == p_skeleton)
 		return;
 
-	if (instance->skeleton.is_valid()) {
-		VSG::storage->instance_remove_skeleton(instance->skeleton, instance);
-	}
-
 	instance->skeleton = p_skeleton;
 
-	if (instance->skeleton.is_valid()) {
-		VSG::storage->instance_add_skeleton(instance->skeleton, instance);
+	if (p_skeleton.is_valid()) {
+		//update the dependency now, so if cleared, we remove it
+		VSG::storage->skeleton_update_dependency(p_skeleton, instance);
 	}
-
-	_instance_queue_update(instance, true);
+	_instance_queue_update(instance, true, true);
 }
 
 void VisualServerScene::instance_set_exterior(RID p_instance, bool p_enabled) {
@@ -875,22 +857,15 @@ void VisualServerScene::instance_geometry_set_cast_shadows_setting(RID p_instanc
 	ERR_FAIL_COND(!instance);
 
 	instance->cast_shadows = p_shadow_casting_setting;
-	instance->base_changed(false, true); // to actually compute if shadows are visible or not
+	_instance_queue_update(instance, false, true);
 }
 void VisualServerScene::instance_geometry_set_material_override(RID p_instance, RID p_material) {
 
 	Instance *instance = instance_owner.getornull(p_instance);
 	ERR_FAIL_COND(!instance);
 
-	if (instance->material_override.is_valid()) {
-		VSG::storage->material_remove_instance_owner(instance->material_override, instance);
-	}
 	instance->material_override = p_material;
-	instance->base_changed(false, true);
-
-	if (instance->material_override.is_valid()) {
-		VSG::storage->material_add_instance_owner(instance->material_override, instance);
-	}
+	_instance_queue_update(instance, false, true);
 }
 
 void VisualServerScene::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) {
@@ -3291,17 +3266,22 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
 		_update_instance_aabb(p_instance);
 	}
 
-	if (p_instance->update_materials) {
+	if (p_instance->update_dependencies) {
+
+		p_instance->instance_increase_version();
+
+		if (p_instance->base.is_valid()) {
+			VSG::storage->base_update_dependency(p_instance->base, p_instance);
+		}
+
+		if (p_instance->material_override.is_valid()) {
+			VSG::storage->material_update_dependency(p_instance->material_override, p_instance);
+		}
 
 		if (p_instance->base_type == VS::INSTANCE_MESH) {
 			//remove materials no longer used and un-own them
 
 			int new_mat_count = VSG::storage->mesh_get_surface_count(p_instance->base);
-			for (int i = p_instance->materials.size() - 1; i >= new_mat_count; i--) {
-				if (p_instance->materials[i].is_valid()) {
-					VSG::storage->material_remove_instance_owner(p_instance->materials[i], p_instance);
-				}
-			}
 			p_instance->materials.resize(new_mat_count);
 
 			int new_blend_shape_count = VSG::storage->mesh_get_blend_shape_count(p_instance->base);
@@ -3348,6 +3328,8 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
 								if (VSG::storage->material_is_animated(mat)) {
 									is_animated = true;
 								}
+
+								VSG::storage->material_update_dependency(mat, p_instance);
 							}
 						}
 
@@ -3378,6 +3360,8 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
 								if (VSG::storage->material_is_animated(mat)) {
 									is_animated = true;
 								}
+
+								VSG::storage->material_update_dependency(mat, p_instance);
 							}
 						}
 
@@ -3394,6 +3378,11 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
 					if (mat.is_valid() && VSG::storage->material_is_animated(mat)) {
 						is_animated = true;
 					}
+
+					if (mat.is_valid()) {
+						VSG::storage->material_update_dependency(mat, p_instance);
+					}
+
 				} else if (p_instance->base_type == VS::INSTANCE_PARTICLES) {
 
 					bool cast_shadows = false;
@@ -3422,6 +3411,8 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
 								if (VSG::storage->material_is_animated(mat)) {
 									is_animated = true;
 								}
+
+								VSG::storage->material_update_dependency(mat, p_instance);
 							}
 						}
 					}
@@ -3444,6 +3435,12 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
 
 			geom->material_is_animated = is_animated;
 		}
+
+		if (p_instance->skeleton.is_valid()) {
+			VSG::storage->skeleton_update_dependency(p_instance->skeleton, p_instance);
+		}
+
+		p_instance->clean_up_dependencies();
 	}
 
 	_instance_update_list.remove(&p_instance->update_item);
@@ -3451,7 +3448,7 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
 	_update_instance(p_instance);
 
 	p_instance->update_aabb = false;
-	p_instance->update_materials = false;
+	p_instance->update_dependencies = false;
 }
 
 void VisualServerScene::update_dirty_instances() {

+ 13 - 9
servers/visual/visual_server_scene.h

@@ -151,7 +151,7 @@ public:
 
 		//aabb stuff
 		bool update_aabb;
-		bool update_materials;
+		bool update_dependencies;
 
 		SelfList<Instance> update_item;
 
@@ -174,14 +174,18 @@ public:
 
 		InstanceBaseData *base_data;
 
-		virtual void base_removed() {
-
-			singleton->instance_set_base(self, RID());
+		virtual void dependency_deleted(RID p_dependency) {
+			if (p_dependency == base) {
+				singleton->instance_set_base(self, RID());
+			} else if (p_dependency == skeleton) {
+				singleton->instance_attach_skeleton(self, RID());
+			} else {
+				singleton->_instance_queue_update(this, false, true);
+			}
 		}
 
-		virtual void base_changed(bool p_aabb, bool p_materials) {
-
-			singleton->_instance_queue_update(this, p_aabb, p_materials);
+		virtual void dependency_changed(bool p_aabb, bool p_dependencies) {
+			singleton->_instance_queue_update(this, p_aabb, p_dependencies);
 		}
 
 		Instance() :
@@ -192,7 +196,7 @@ public:
 			scenario = NULL;
 
 			update_aabb = false;
-			update_materials = false;
+			update_dependencies = false;
 
 			extra_margin = 0;
 
@@ -222,7 +226,7 @@ public:
 	};
 
 	SelfList<Instance>::List _instance_update_list;
-	void _instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_materials = false);
+	void _instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies = false);
 
 	struct InstanceGeometryData : public InstanceBaseData {
 

+ 0 - 1
servers/visual/visual_server_wrap_mt.h

@@ -140,7 +140,6 @@ public:
 	FUNCRID(material)
 
 	FUNC2(material_set_shader, RID, RID)
-	FUNC1RC(RID, material_get_shader, RID)
 
 	FUNC3(material_set_param, RID, const StringName &, const Variant &)
 	FUNC2RC(Variant, material_get_param, RID, const StringName &)

+ 1 - 1
servers/visual_server.cpp

@@ -1652,7 +1652,6 @@ void VisualServer::_bind_methods() {
 
 	ClassDB::bind_method(D_METHOD("material_create"), &VisualServer::material_create);
 	ClassDB::bind_method(D_METHOD("material_set_shader", "shader_material", "shader"), &VisualServer::material_set_shader);
-	ClassDB::bind_method(D_METHOD("material_get_shader", "shader_material"), &VisualServer::material_get_shader);
 	ClassDB::bind_method(D_METHOD("material_set_param", "material", "parameter", "value"), &VisualServer::material_set_param);
 	ClassDB::bind_method(D_METHOD("material_get_param", "material", "parameter"), &VisualServer::material_get_param);
 	ClassDB::bind_method(D_METHOD("material_set_render_priority", "material", "priority"), &VisualServer::material_set_render_priority);
@@ -2365,6 +2364,7 @@ VisualServer::VisualServer() {
 	GLOBAL_DEF("rendering/quality/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno,Apple");
 
 	GLOBAL_DEF("rendering/quality/filters/use_nearest_mipmap_filter", false);
+	GLOBAL_DEF("rendering/quality/filters/max_anisotropy", 4);
 }
 
 VisualServer::~VisualServer() {

+ 3 - 2
servers/visual_server.h

@@ -192,7 +192,6 @@ public:
 	virtual RID material_create() = 0;
 
 	virtual void material_set_shader(RID p_shader_material, RID p_shader) = 0;
-	virtual RID material_get_shader(RID p_shader_material) const = 0;
 
 	virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) = 0;
 	virtual Variant material_get_param(RID p_material, const StringName &p_param) const = 0;
@@ -884,8 +883,10 @@ public:
 		CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, //uses canvas item setting for draw command, uses global setting for canvas item
 		CANVAS_ITEM_TEXTURE_FILTER_NEAREST,
 		CANVAS_ITEM_TEXTURE_FILTER_LINEAR,
-		CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS,
 		CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS,
+		CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS,
+		CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC,
+		CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC,
 		CANVAS_ITEM_TEXTURE_FILTER_MAX
 	};