diff options
20 files changed, 561 insertions, 55 deletions
| diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 92d7906b6c..913516889e 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -2947,7 +2947,7 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,  		image_memory_barrier.srcAccessMask = valid_texture_access;  		image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;  		image_memory_barrier.oldLayout = src_tex->layout; -		image_memory_barrier.oldLayout = clear_layout; +		image_memory_barrier.newLayout = clear_layout;  		image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;  		image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -6795,13 +6795,12 @@ void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) {  void RenderingDeviceVulkan::compute_list_end() {  	ERR_FAIL_COND(!compute_list); -	const VkPipelineStageFlags dest_stage_mask = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;  	for (Set<Texture *>::Element *E = compute_list->state.textures_to_sampled_layout.front(); E; E = E->next()) {  		VkImageMemoryBarrier image_memory_barrier;  		image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;  		image_memory_barrier.pNext = nullptr;  		image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; -		image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT; +		image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT;  		image_memory_barrier.oldLayout = E->get()->layout;  		image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -6815,7 +6814,7 @@ void RenderingDeviceVulkan::compute_list_end() {  		image_memory_barrier.subresourceRange.layerCount = E->get()->layers;  		// TODO: Look at the usages in the compute list and determine tighter dst stage and access masks based on some "final" usage equivalent -		vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, dest_stage_mask, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); +		vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);  		E->get()->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;  	} @@ -6825,7 +6824,7 @@ void RenderingDeviceVulkan::compute_list_end() {  #ifdef FORCE_FULL_BARRIER  	_full_barrier(true);  #else -	_memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, dest_stage_mask, VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT, true); +	_memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT, true);  #endif  } diff --git a/scene/2d/canvas_group.cpp b/scene/2d/canvas_group.cpp new file mode 100644 index 0000000000..39cae8e0c6 --- /dev/null +++ b/scene/2d/canvas_group.cpp @@ -0,0 +1,87 @@ +/*************************************************************************/ +/*  canvas_group.cpp                                                     */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +#include "canvas_group.h" + +void CanvasGroup::set_fit_margin(float p_fit_margin) { +	ERR_FAIL_COND(p_fit_margin < 0.0); + +	fit_margin = p_fit_margin; +	RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CANVAS_GROUP_MODE_TRANSPARENT, clear_margin, true, fit_margin, use_mipmaps); + +	update(); +} + +float CanvasGroup::get_fit_margin() const { +	return fit_margin; +} + +void CanvasGroup::set_clear_margin(float p_clear_margin) { +	ERR_FAIL_COND(p_clear_margin < 0.0); + +	clear_margin = p_clear_margin; +	RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CANVAS_GROUP_MODE_TRANSPARENT, clear_margin, true, clear_margin, use_mipmaps); + +	update(); +} + +float CanvasGroup::get_clear_margin() const { +	return clear_margin; +} + +void CanvasGroup::set_use_mipmaps(bool p_use_mipmaps) { +	use_mipmaps = p_use_mipmaps; +	RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CANVAS_GROUP_MODE_TRANSPARENT, clear_margin, true, fit_margin, use_mipmaps); +} +bool CanvasGroup::is_using_mipmaps() const { +	return use_mipmaps; +} + +void CanvasGroup::_bind_methods() { +	ClassDB::bind_method(D_METHOD("set_fit_margin", "fit_margin"), &CanvasGroup::set_fit_margin); +	ClassDB::bind_method(D_METHOD("get_fit_margin"), &CanvasGroup::get_fit_margin); + +	ClassDB::bind_method(D_METHOD("set_clear_margin", "clear_margin"), &CanvasGroup::set_clear_margin); +	ClassDB::bind_method(D_METHOD("get_clear_margin"), &CanvasGroup::get_clear_margin); + +	ClassDB::bind_method(D_METHOD("set_use_mipmaps", "use_mipmaps"), &CanvasGroup::set_use_mipmaps); +	ClassDB::bind_method(D_METHOD("is_using_mipmaps"), &CanvasGroup::is_using_mipmaps); + +	ADD_GROUP("Tweaks", ""); +	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fit_margin", PROPERTY_HINT_RANGE, "0,1024,1.0,or_greater"), "set_fit_margin", "get_fit_margin"); +	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "clear_margin", PROPERTY_HINT_RANGE, "0,1024,1.0,or_greater"), "set_clear_margin", "get_clear_margin"); +	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_mipmaps"), "set_use_mipmaps", "is_using_mipmaps"); +} + +CanvasGroup::CanvasGroup() { +	set_fit_margin(10.0); //sets things +} +CanvasGroup::~CanvasGroup() { +} diff --git a/scene/2d/canvas_group.h b/scene/2d/canvas_group.h new file mode 100644 index 0000000000..19630befc7 --- /dev/null +++ b/scene/2d/canvas_group.h @@ -0,0 +1,59 @@ +/*************************************************************************/ +/*  canvas_group.h                                                       */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +#ifndef CANVASGROUP_H +#define CANVASGROUP_H + +#include "scene/2d/node_2d.h" + +class CanvasGroup : public Node2D { +	GDCLASS(CanvasGroup, Node2D) +	float fit_margin = 10.0; +	float clear_margin = 10.0; +	bool use_mipmaps = false; + +protected: +	static void _bind_methods(); + +public: +	void set_fit_margin(float p_fit_margin); +	float get_fit_margin() const; + +	void set_clear_margin(float p_clear_margin); +	float get_clear_margin() const; + +	void set_use_mipmaps(bool p_use_mipmaps); +	bool is_using_mipmaps() const; + +	CanvasGroup(); +	~CanvasGroup(); +}; + +#endif // CANVASGROUP_H diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 6323b55378..740374d09e 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -32,6 +32,7 @@  #include "core/input/input.h"  #include "core/message_queue.h" +#include "scene/2d/canvas_group.h"  #include "scene/main/canvas_layer.h"  #include "scene/main/viewport.h"  #include "scene/main/window.h" @@ -1199,6 +1200,9 @@ void CanvasItem::_bind_methods() {  	ClassDB::bind_method(D_METHOD("set_texture_repeat", "mode"), &CanvasItem::set_texture_repeat);  	ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasItem::get_texture_repeat); +	ClassDB::bind_method(D_METHOD("set_clip_children", "enable"), &CanvasItem::set_clip_children); +	ClassDB::bind_method(D_METHOD("is_clipping_children"), &CanvasItem::is_clipping_children); +  	BIND_VMETHOD(MethodInfo("_draw"));  	ADD_GROUP("Visibility", ""); @@ -1208,6 +1212,7 @@ void CanvasItem::_bind_methods() {  	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled");  	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level");  	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_on_top", PROPERTY_HINT_NONE, "", 0), "_set_on_top", "_is_on_top"); //compatibility +	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_children"), "set_clip_children", "is_clipping_children");  	ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");  	ADD_GROUP("Texture", "texture_"); @@ -1383,6 +1388,22 @@ void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {  	_change_notify();  } +void CanvasItem::set_clip_children(bool p_enabled) { +	if (clip_children == p_enabled) { +		return; +	} +	clip_children = p_enabled; + +	if (Object::cast_to<CanvasGroup>(this) != nullptr) { +		//avoid accidental bugs, make this not work on CanvasGroup +		return; +	} +	RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), clip_children ? RS::CANVAS_GROUP_MODE_OPAQUE : RS::CANVAS_GROUP_MODE_DISABLED); +} +bool CanvasItem::is_clipping_children() const { +	return clip_children; +} +  CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {  	return texture_repeat;  } @@ -1399,6 +1420,7 @@ CanvasItem::CanvasItem() :  	first_draw = false;  	drawing = false;  	behind = false; +	clip_children = false;  	block_transform_notify = false;  	canvas_layer = nullptr;  	use_parent_material = false; diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 092fd17df3..412ef8079b 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -200,6 +200,7 @@ private:  	Window *window;  	bool first_draw;  	bool visible; +	bool clip_children;  	bool pending_update;  	bool top_level;  	bool drawing; @@ -315,6 +316,9 @@ public:  	void update(); +	void set_clip_children(bool p_enabled); +	bool is_clipping_children() const; +  	virtual void set_light_mask(int p_light_mask);  	int get_light_mask() const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 76b68c8da8..f1dcc8e8a5 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -38,6 +38,7 @@  #include "scene/2d/audio_stream_player_2d.h"  #include "scene/2d/back_buffer_copy.h"  #include "scene/2d/camera_2d.h" +#include "scene/2d/canvas_group.h"  #include "scene/2d/canvas_modulate.h"  #include "scene/2d/collision_polygon_2d.h"  #include "scene/2d/collision_shape_2d.h" @@ -602,6 +603,7 @@ void register_scene_types() {  	/* REGISTER 2D */  	ClassDB::register_class<Node2D>(); +	ClassDB::register_class<CanvasGroup>();  	ClassDB::register_class<CPUParticles2D>();  	ClassDB::register_class<GPUParticles2D>();  	ClassDB::register_class<Sprite2D>(); diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index ad9d888480..a0ce6e1194 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -458,8 +458,19 @@ DynamicFontAtSize::TexturePosition DynamicFontAtSize::_find_texture_pos_for_glyp  			//zero texture  			uint8_t *w = tex.imgdata.ptrw();  			ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.size(), ret); -			for (int i = 0; i < texsize * texsize * p_color_size; i++) { -				w[i] = 0; + +			if (p_color_size == 2) { +				for (int i = 0; i < texsize * texsize * p_color_size; i += 2) { +					w[i + 0] = 255; +					w[i + 1] = 0; +				} +			} else { +				for (int i = 0; i < texsize * texsize * p_color_size; i += 4) { +					w[i + 0] = 255; +					w[i + 1] = 255; +					w[i + 2] = 255; +					w[i + 3] = 0; +				}  			}  		}  		tex.offsets.resize(texsize); diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h index 4ece811a1e..88b92bd35d 100644 --- a/servers/rendering/rasterizer.h +++ b/servers/rendering/rasterizer.h @@ -815,7 +815,8 @@ public:  		CANVAS_RECT_FLIP_H = 4,  		CANVAS_RECT_FLIP_V = 8,  		CANVAS_RECT_TRANSPOSE = 16, -		CANVAS_RECT_CLIP_UV = 32 +		CANVAS_RECT_CLIP_UV = 32, +		CANVAS_RECT_IS_GROUP = 64,  	};  	struct Light { @@ -1060,7 +1061,16 @@ public:  		bool visible;  		bool behind;  		bool update_when_visible; -		//RS::MaterialBlendMode blend_mode; + +		struct CanvasGroup { +			RS::CanvasGroupMode mode; +			bool fit_empty; +			float fit_margin; +			bool blur_mipmaps; +			float clear_margin; +		}; + +		CanvasGroup *canvas_group = nullptr;  		int light_mask;  		int z_final; @@ -1084,6 +1094,7 @@ public:  		Rect2 final_clip_rect;  		Item *final_clip_owner;  		Item *material_owner; +		Item *canvas_group_owner;  		ViewportRender *vp_render;  		bool distance_field;  		bool light_masked; @@ -1242,6 +1253,8 @@ public:  		}  		void clear() { +			// The first one is always allocated on heap +			// the rest go in the blocks  			Command *c = commands;  			while (c) {  				Command *n = c->next; @@ -1282,6 +1295,7 @@ public:  			vp_render = nullptr;  			next = nullptr;  			final_clip_owner = nullptr; +			canvas_group_owner = nullptr;  			clip = false;  			final_modulate = Color(1, 1, 1, 1);  			visible = true; diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp index 28674b118c..b268db5989 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp @@ -1102,28 +1102,36 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_  	return uniform_set;  } -void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights) { +void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer) {  	Item *current_clip = nullptr;  	Transform2D canvas_transform_inverse = p_canvas_transform_inverse; -	RID framebuffer = storage->render_target_get_rd_framebuffer(p_to_render_target); - -	Vector<Color> clear_colors; +	RID framebuffer; +	RID fb_uniform_set;  	bool clear = false; -	if (storage->render_target_is_clear_requested(p_to_render_target)) { -		clear = true; -		clear_colors.push_back(storage->render_target_get_clear_request_color(p_to_render_target)); -		storage->render_target_disable_clear_request(p_to_render_target); -	} +	Vector<Color> clear_colors; + +	if (p_to_backbuffer) { +		framebuffer = storage->render_target_get_rd_backbuffer_framebuffer(p_to_render_target); +		fb_uniform_set = storage->render_target_get_backbuffer_uniform_set(p_to_render_target); +	} else { +		framebuffer = storage->render_target_get_rd_framebuffer(p_to_render_target); + +		if (storage->render_target_is_clear_requested(p_to_render_target)) { +			clear = true; +			clear_colors.push_back(storage->render_target_get_clear_request_color(p_to_render_target)); +			storage->render_target_disable_clear_request(p_to_render_target); +		}  #ifndef _MSC_VER  #warning TODO obtain from framebuffer format eventually when this is implemented  #endif -	RID fb_uniform_set = storage->render_target_get_framebuffer_uniform_set(p_to_render_target); +		fb_uniform_set = storage->render_target_get_framebuffer_uniform_set(p_to_render_target); +	}  	if (fb_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(fb_uniform_set)) { -		fb_uniform_set = _create_base_uniform_set(p_to_render_target, false); +		fb_uniform_set = _create_base_uniform_set(p_to_render_target, p_to_backbuffer);  	}  	RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); @@ -1152,10 +1160,16 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count,  			}  		} -		if (ci->material != prev_material) { +		RID material = ci->material; + +		if (material.is_null() && ci->canvas_group != nullptr) { +			material = default_canvas_group_material; +		} + +		if (material != prev_material) {  			MaterialData *material_data = nullptr; -			if (ci->material.is_valid()) { -				material_data = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D); +			if (material.is_valid()) { +				material_data = (MaterialData *)storage->material_get_data(material, RasterizerStorageRD::SHADER_TYPE_2D);  			}  			if (material_data) { @@ -1174,7 +1188,7 @@ 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, pipeline_variants); -		prev_material = ci->material; +		prev_material = material;  	}  	RD::get_singleton()->draw_list_end(); @@ -1306,8 +1320,10 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite  	Rect2 back_buffer_rect;  	bool backbuffer_copy = false; +	Item *canvas_group_owner = nullptr; +  	while (ci) { -		if (ci->copy_back_buffer) { +		if (ci->copy_back_buffer && canvas_group_owner == nullptr) {  			backbuffer_copy = true;  			if (ci->copy_back_buffer->full) { @@ -1320,7 +1336,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite  		if (ci->material.is_valid()) {  			MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D);  			if (md && md->shader_data->valid) { -				if (md->shader_data->uses_screen_texture) { +				if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) {  					if (!material_screen_texture_found) {  						backbuffer_copy = true;  						back_buffer_rect = Rect2(); @@ -1338,12 +1354,44 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite  			}  		} +		if (ci->canvas_group_owner != nullptr) { +			if (canvas_group_owner == nullptr) { +				//Canvas group begins here, render until before this item +				_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list); +				item_count = 0; + +				Rect2i group_rect = ci->canvas_group_owner->global_rect_cache; + +				if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_OPAQUE) { +					storage->render_target_copy_to_back_buffer(p_to_render_target, group_rect, false); +				} else { +					storage->render_target_clear_back_buffer(p_to_render_target, group_rect, Color(0, 0, 0, 0)); +				} + +				backbuffer_copy = false; +				canvas_group_owner = ci->canvas_group_owner; //continue until owner found +			} + +			ci->canvas_group_owner = nullptr; //must be cleared +		} + +		if (ci == canvas_group_owner) { +			_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, true); +			item_count = 0; + +			if (ci->canvas_group->blur_mipmaps) { +				storage->render_target_gen_back_buffer_mipmaps(p_to_render_target, ci->global_rect_cache); +			} + +			canvas_group_owner = nullptr; +		} +  		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);  			item_count = 0; -			storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect); +			storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, true);  			backbuffer_copy = false;  			material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies @@ -1672,10 +1720,11 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) {  		} 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.alpha_blend_op = RD::BLEND_OP_ADD;  			attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;  			attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; @@ -2013,6 +2062,20 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {  		shader.default_version = shader.canvas_shader.version_create();  		shader.default_version_rd_shader = shader.canvas_shader.version_get_shader(shader.default_version, SHADER_VARIANT_QUAD); +		RD::PipelineColorBlendState blend_state; +		RD::PipelineColorBlendState::Attachment blend_attachment; + +		blend_attachment.enable_blend = true; +		blend_attachment.color_blend_op = RD::BLEND_OP_ADD; +		blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; +		blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + +		blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; +		blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; +		blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + +		blend_state.attachments.push_back(blend_attachment); +  		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] = { @@ -2054,7 +2117,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {  				};  				RID shader_variant = shader.canvas_shader.version_get_shader(shader.default_version, shader_variants[i][j]); -				shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0); +				shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);  			}  		}  	} @@ -2260,6 +2323,13 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {  	state.time = 0; +	{ +		default_canvas_group_shader = storage->shader_create(); +		storage->shader_set_code(default_canvas_group_shader, "shader_type canvas_item; \nvoid fragment() {\n\tvec4 c = textureLod(SCREEN_TEXTURE,SCREEN_UV,0.0); if (c.a > 0.0001) c.rgb/=c.a; COLOR *= c; \n}\n"); +		default_canvas_group_material = storage->material_create(); +		storage->material_set_shader(default_canvas_group_material, default_canvas_group_shader); +	} +  	static_assert(sizeof(PushConstant) == 128);  } @@ -2307,6 +2377,9 @@ void RasterizerCanvasRD::set_shadow_texture_size(int p_size) {  RasterizerCanvasRD::~RasterizerCanvasRD() {  	//canvas state +	storage->free(default_canvas_group_material); +	storage->free(default_canvas_group_shader); +  	{  		if (state.canvas_state_buffer.is_valid()) {  			RD::get_singleton()->free(state.canvas_state_buffer); diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h index 5791efa4e5..4a79134c24 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h @@ -391,6 +391,9 @@ class RasterizerCanvasRD : public RasterizerCanvas {  	RID default_canvas_texture; +	RID default_canvas_group_shader; +	RID default_canvas_group_material; +  	RS::CanvasItemTextureFilter default_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;  	RS::CanvasItemTextureRepeat default_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; @@ -398,7 +401,7 @@ class RasterizerCanvasRD : public RasterizerCanvas {  	inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size); //recursive, so regular inline used instead.  	void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_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); +	void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer = false);  	_FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);  	_FORCE_INLINE_ void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3); diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp index 409cfdfecf..d669db1b4b 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp @@ -246,7 +246,7 @@ void RasterizerEffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_fr  	RD::get_singleton()->draw_list_end();  } -void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst) { +void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst, bool p_alpha_to_one) {  	zeromem(©.push_constant, sizeof(CopyPushConstant));  	if (p_flip_y) {  		copy.push_constant.flags |= COPY_FLAG_FLIP_Y; @@ -260,6 +260,10 @@ void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_textu  		copy.push_constant.flags |= COPY_FLAG_ALL_SOURCE;  	} +	if (p_alpha_to_one) { +		copy.push_constant.flags |= COPY_FLAG_ALPHA_TO_ONE; +	} +  	copy.push_constant.section[0] = 0;  	copy.push_constant.section[1] = 0;  	copy.push_constant.section[2] = p_rect.size.width; @@ -354,6 +358,31 @@ void RasterizerEffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest  	RD::get_singleton()->compute_list_end();  } +void RasterizerEffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst) { +	zeromem(©.push_constant, sizeof(CopyPushConstant)); + +	copy.push_constant.section[0] = 0; +	copy.push_constant.section[1] = 0; +	copy.push_constant.section[2] = p_region.size.width; +	copy.push_constant.section[3] = p_region.size.height; +	copy.push_constant.target[0] = p_region.position.x; +	copy.push_constant.target[1] = p_region.position.y; +	copy.push_constant.set_color[0] = p_color.r; +	copy.push_constant.set_color[1] = p_color.g; +	copy.push_constant.set_color[2] = p_color.b; +	copy.push_constant.set_color[3] = p_color.a; + +	int32_t x_groups = (p_region.size.width - 1) / 8 + 1; +	int32_t y_groups = (p_region.size.height - 1) / 8 + 1; + +	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8bit_dst ? COPY_MODE_SET_COLOR_8BIT : COPY_MODE_SET_COLOR]); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); +	RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); +	RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); +	RD::get_singleton()->compute_list_end(); +} +  void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) {  	zeromem(©.push_constant, sizeof(CopyPushConstant)); @@ -369,7 +398,7 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture,  	RD::DrawListID compute_list = RD::get_singleton()->compute_list_begin();  	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8bit_dst ? COPY_MODE_GAUSSIAN_COPY_8BIT : COPY_MODE_GAUSSIAN_COPY]);  	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); -	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 0); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 3);  	copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL;  	RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); @@ -380,7 +409,7 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture,  	//VERTICAL  	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_back_texture), 0); -	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 0); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 3);  	copy.push_constant.flags = base_flags;  	RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); @@ -1346,6 +1375,8 @@ RasterizerEffectsRD::RasterizerEffectsRD() {  		copy_modes.push_back("\n#define MODE_SIMPLE_COPY\n");  		copy_modes.push_back("\n#define MODE_SIMPLE_COPY\n#define DST_IMAGE_8BIT\n");  		copy_modes.push_back("\n#define MODE_SIMPLE_COPY_DEPTH\n"); +		copy_modes.push_back("\n#define MODE_SET_COLOR\n"); +		copy_modes.push_back("\n#define MODE_SET_COLOR\n#define DST_IMAGE_8BIT\n");  		copy_modes.push_back("\n#define MODE_MIPMAP\n");  		copy_modes.push_back("\n#define MODE_LINEARIZE_DEPTH_COPY\n");  		copy_modes.push_back("\n#define MODE_CUBEMAP_TO_PANORAMA\n"); diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h index 679263fbf6..a0bdd59fd2 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h @@ -66,6 +66,8 @@ class RasterizerEffectsRD {  		COPY_MODE_SIMPLY_COPY,  		COPY_MODE_SIMPLY_COPY_8BIT,  		COPY_MODE_SIMPLY_COPY_DEPTH, +		COPY_MODE_SET_COLOR, +		COPY_MODE_SET_COLOR_8BIT,  		COPY_MODE_MIPMAP,  		COPY_MODE_LINEARIZE_DEPTH,  		COPY_MODE_CUBE_TO_PANORAMA, @@ -83,7 +85,8 @@ class RasterizerEffectsRD {  		COPY_FLAG_FLIP_Y = (1 << 5),  		COPY_FLAG_FORCE_LUMINANCE = (1 << 6),  		COPY_FLAG_ALL_SOURCE = (1 << 7), -		COPY_FLAG_HIGH_QUALITY_GLOW = (1 << 8) +		COPY_FLAG_HIGH_QUALITY_GLOW = (1 << 8), +		COPY_FLAG_ALPHA_TO_ONE = (1 << 9),  	};  	struct CopyPushConstant { @@ -105,6 +108,8 @@ class RasterizerEffectsRD {  		float camera_z_far;  		float camera_z_near;  		uint32_t pad2[2]; +		//SET color +		float set_color[4];  	};  	struct Copy { @@ -603,12 +608,13 @@ class RasterizerEffectsRD {  public:  	void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID()); -	void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false); +	void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false);  	void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array);  	void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false);  	void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far);  	void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false);  	void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false); +	void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false);  	void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);  	void cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp index b47d724147..10c9293d67 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp @@ -6131,12 +6131,18 @@ void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) {  	tf.width = rt->size.width;  	tf.height = rt->size.height;  	tf.type = RD::TEXTURE_TYPE_2D; -	tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; +	tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;  	tf.mipmaps = mipmaps_required;  	rt->backbuffer = RD::get_singleton()->texture_create(tf, RD::TextureView());  	rt->backbuffer_mipmap0 = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, 0); +	{ +		Vector<RID> fb_tex; +		fb_tex.push_back(rt->backbuffer_mipmap0); +		rt->backbuffer_fb = RD::get_singleton()->framebuffer_create(fb_tex); +	} +  	if (rt->framebuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->framebuffer_uniform_set)) {  		//the new one will require the backbuffer.  		RD::get_singleton()->free(rt->framebuffer_uniform_set); @@ -6245,6 +6251,17 @@ RID RasterizerStorageRD::render_target_get_rd_backbuffer(RID p_render_target) {  	return rt->backbuffer;  } +RID RasterizerStorageRD::render_target_get_rd_backbuffer_framebuffer(RID p_render_target) { +	RenderTarget *rt = render_target_owner.getornull(p_render_target); +	ERR_FAIL_COND_V(!rt, RID()); + +	if (!rt->backbuffer.is_valid()) { +		_create_render_target_backbuffer(rt); +	} + +	return rt->backbuffer_fb; +} +  void RasterizerStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {  	RenderTarget *rt = render_target_owner.getornull(p_render_target);  	ERR_FAIL_COND(!rt); @@ -6283,21 +6300,30 @@ void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) {  	rt->clear_requested = false;  } -void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region) { +void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) {  	RenderTarget *rt = render_target_owner.getornull(p_render_target);  	ERR_FAIL_COND(!rt);  	if (!rt->backbuffer.is_valid()) {  		_create_render_target_backbuffer(rt);  	} -	Rect2i region = p_region; -	if (region == Rect2i()) { +	Rect2i region; +	if (p_region == Rect2i()) {  		region.size = rt->size; +	} else { +		region = Rect2i(Size2i(), rt->size).clip(p_region); +		if (region.size == Size2i()) { +			return; //nothing to do +		}  	}  	//single texture copy for backbuffer -	RD::get_singleton()->texture_copy(rt->color, rt->backbuffer_mipmap0, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true); -	//effects.copy(rt->color, rt->backbuffer_fb, blur_region); +	//RD::get_singleton()->texture_copy(rt->color, rt->backbuffer_mipmap0, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true); +	effects.copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, true, true); + +	if (!p_gen_mipmaps) { +		return; +	}  	//then mipmap blur  	RID prev_texture = rt->color; //use color, not backbuffer, as bb has mipmaps. @@ -6314,6 +6340,59 @@ void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target,  	}  } +void RasterizerStorageRD::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) { +	RenderTarget *rt = render_target_owner.getornull(p_render_target); +	ERR_FAIL_COND(!rt); +	if (!rt->backbuffer.is_valid()) { +		_create_render_target_backbuffer(rt); +	} + +	Rect2i region; +	if (p_region == Rect2i()) { +		region.size = rt->size; +	} else { +		region = Rect2i(Size2i(), rt->size).clip(p_region); +		if (region.size == Size2i()) { +			return; //nothing to do +		} +	} + +	//single texture copy for backbuffer +	effects.set_color(rt->backbuffer_mipmap0, p_color, region, true); +} + +void RasterizerStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) { +	RenderTarget *rt = render_target_owner.getornull(p_render_target); +	ERR_FAIL_COND(!rt); +	if (!rt->backbuffer.is_valid()) { +		_create_render_target_backbuffer(rt); +	} + +	Rect2i region; +	if (p_region == Rect2i()) { +		region.size = rt->size; +	} else { +		region = Rect2i(Size2i(), rt->size).clip(p_region); +		if (region.size == Size2i()) { +			return; //nothing to do +		} +	} + +	//then mipmap blur +	RID prev_texture = rt->backbuffer_mipmap0; + +	for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) { +		region.position.x >>= 1; +		region.position.y >>= 1; +		region.size.x = MAX(1, region.size.x >> 1); +		region.size.y = MAX(1, region.size.y >> 1); + +		const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i]; +		effects.gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true); +		prev_texture = mm.mipmap; +	} +} +  RID RasterizerStorageRD::render_target_get_framebuffer_uniform_set(RID p_render_target) {  	RenderTarget *rt = render_target_owner.getornull(p_render_target);  	ERR_FAIL_COND_V(!rt, RID()); diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h index 7caafca2e0..321bff9fdd 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h @@ -989,6 +989,7 @@ private:  		bool flags[RENDER_TARGET_FLAG_MAX];  		RID backbuffer; //used for effects +		RID backbuffer_fb;  		RID backbuffer_mipmap0;  		struct BackbufferMipmap { @@ -1916,7 +1917,9 @@ public:  	void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);  	bool render_target_was_used(RID p_render_target);  	void render_target_set_as_unused(RID p_render_target); -	void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region); +	void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps); +	void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color); +	void render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region);  	RID render_target_get_back_buffer_uniform_set(RID p_render_target, RID p_base_shader); @@ -1930,6 +1933,7 @@ public:  	RID render_target_get_rd_framebuffer(RID p_render_target);  	RID render_target_get_rd_texture(RID p_render_target);  	RID render_target_get_rd_backbuffer(RID p_render_target); +	RID render_target_get_rd_backbuffer_framebuffer(RID p_render_target);  	RID render_target_get_framebuffer_uniform_set(RID p_render_target);  	RID render_target_get_backbuffer_uniform_set(RID p_render_target); diff --git a/servers/rendering/rasterizer_rd/shaders/copy.glsl b/servers/rendering/rasterizer_rd/shaders/copy.glsl index 355a2b9d75..cdd35dfb3f 100644 --- a/servers/rendering/rasterizer_rd/shaders/copy.glsl +++ b/servers/rendering/rasterizer_rd/shaders/copy.glsl @@ -15,6 +15,7 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;  #define FLAG_FORCE_LUMINANCE (1 << 6)  #define FLAG_COPY_ALL_SOURCE (1 << 7)  #define FLAG_HIGH_QUALITY_GLOW (1 << 8) +#define FLAG_ALPHA_TO_ONE (1 << 9)  layout(push_constant, binding = 1, std430) uniform Params {  	ivec4 section; @@ -35,6 +36,8 @@ layout(push_constant, binding = 1, std430) uniform Params {  	float camera_z_far;  	float camera_z_near;  	uint pad2[2]; + +	vec4 set_color;  }  params; @@ -42,7 +45,7 @@ params;  layout(set = 0, binding = 0) uniform samplerCubeArray source_color;  #elif defined(MODE_CUBEMAP_TO_PANORAMA)  layout(set = 0, binding = 0) uniform samplerCube source_color; -#else +#elif !defined(MODE_SET_COLOR)  layout(set = 0, binding = 0) uniform sampler2D source_color;  #endif @@ -203,25 +206,24 @@ void main() {  		}  		color = textureLod(source_color, uv, 0.0); -		if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { -			color.rgb = vec3(max(max(color.r, color.g), color.b)); -		} -		imageStore(dest_buffer, pos + params.target, color); -  	} else {  		color = texelFetch(source_color, pos + params.section.xy, 0); -		if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { -			color.rgb = vec3(max(max(color.r, color.g), color.b)); -		} -  		if (bool(params.flags & FLAG_FLIP_Y)) {  			pos.y = params.section.w - pos.y - 1;  		} +	} -		imageStore(dest_buffer, pos + params.target, color); +	if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { +		color.rgb = vec3(max(max(color.r, color.g), color.b)); +	} + +	if (bool(params.flags & FLAG_ALPHA_TO_ONE)) { +		color.a = 1.0;  	} +	imageStore(dest_buffer, pos + params.target, color); +  #endif  #ifdef MODE_SIMPLE_COPY_DEPTH @@ -270,4 +272,8 @@ void main() {  #endif  	imageStore(dest_buffer, pos + params.target, color);  #endif + +#ifdef MODE_SET_COLOR +	imageStore(dest_buffer, pos + params.target, params.set_color); +#endif  } diff --git a/servers/rendering/rendering_server_canvas.cpp b/servers/rendering/rendering_server_canvas.cpp index b0bff8b2c2..f06667a460 100644 --- a/servers/rendering/rendering_server_canvas.cpp +++ b/servers/rendering/rendering_server_canvas.cpp @@ -167,8 +167,15 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo  		p_z = ci->z_index;  	} +	RasterizerCanvas::Item *canvas_group_from = nullptr; +	bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr); +	if (use_canvas_group) { +		int zidx = p_z - RS::CANVAS_ITEM_Z_MIN; +		canvas_group_from = z_last_list[zidx]; +	} +  	for (int i = 0; i < child_item_count; i++) { -		if (!child_items[i]->behind || (ci->sort_y && child_items[i]->sort_y)) { +		if ((!child_items[i]->behind && !use_canvas_group) || (ci->sort_y && child_items[i]->sort_y)) {  			continue;  		}  		if (ci->sort_y) { @@ -182,6 +189,70 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo  		ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).clip(p_clip_rect);  	} +	if (use_canvas_group) { +		int zidx = p_z - RS::CANVAS_ITEM_Z_MIN; +		if (canvas_group_from == nullptr) { +			// no list before processing this item, means must put stuff in group from the beginning of list. +			canvas_group_from = z_list[zidx]; +		} else { +			// there was a list before processing, so begin group from this one. +			canvas_group_from = canvas_group_from->next; +		} + +		if (canvas_group_from) { +			// Has a place to begin the group from! + +			//compute a global rect (in global coords) for children in the same z layer +			Rect2 rect_accum; +			RasterizerCanvas::Item *c = canvas_group_from; +			while (c) { +				if (c == canvas_group_from) { +					rect_accum = c->global_rect_cache; +				} else { +					rect_accum = rect_accum.merge(c->global_rect_cache); +				} + +				c = c->next; +			} + +			// We have two choices now, if user has drawn something, we must assume users wants to draw the "mask", so compute the size based on this. +			// If nothing has been drawn, we just take it over and draw it ourselves. +			if (ci->canvas_group->fit_empty && (ci->commands == nullptr || +													   (ci->commands->next == nullptr && ci->commands->type == Item::Command::TYPE_RECT && (static_cast<Item::CommandRect *>(ci->commands)->flags & RasterizerCanvas::CANVAS_RECT_IS_GROUP)))) { +				// No commands, or sole command is the one used to draw, so we (re)create the draw command. +				ci->clear(); + +				if (rect_accum == Rect2()) { +					rect_accum.size = Size2(1, 1); +				} + +				rect_accum = rect_accum.grow(ci->canvas_group->fit_margin); + +				//draw it? +				RasterizerCanvas::Item::CommandRect *crect = ci->alloc_command<RasterizerCanvas::Item::CommandRect>(); + +				crect->flags = RasterizerCanvas::CANVAS_RECT_IS_GROUP; // so we can recognize it later +				crect->rect = xform.affine_inverse().xform(rect_accum); +				crect->modulate = Color(1, 1, 1, 1); + +				//the global rect is used to do the copying, so update it +				global_rect = rect_accum.grow(ci->canvas_group->clear_margin); //grow again by clear margin +				global_rect.position += p_clip_rect.position; +			} else { +				global_rect.position -= p_clip_rect.position; + +				global_rect = global_rect.merge(rect_accum); //must use both rects for this +				global_rect = global_rect.grow(ci->canvas_group->clear_margin); //grow by clear margin + +				global_rect.position += p_clip_rect.position; +			} + +			// Very important that this is cleared after used in RasterizerCanvas to avoid +			// potential crashes. +			canvas_group_from->canvas_group_owner = ci; +		} +	} +  	if (ci->update_when_visible) {  		RenderingServerRaster::redraw_request();  	} @@ -211,7 +282,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo  	}  	for (int i = 0; i < child_item_count; i++) { -		if (child_items[i]->behind || (ci->sort_y && child_items[i]->sort_y)) { +		if (child_items[i]->behind || use_canvas_group || (ci->sort_y && child_items[i]->sort_y)) {  			continue;  		}  		if (ci->sort_y) { @@ -935,6 +1006,27 @@ void RenderingServerCanvas::canvas_item_set_use_parent_material(RID p_item, bool  	canvas_item->use_parent_material = p_enable;  } +void RenderingServerCanvas::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) { +	Item *canvas_item = canvas_item_owner.getornull(p_item); +	ERR_FAIL_COND(!canvas_item); + +	if (p_mode == RS::CANVAS_GROUP_MODE_DISABLED) { +		if (canvas_item->canvas_group != nullptr) { +			memdelete(canvas_item->canvas_group); +			canvas_item->canvas_group = nullptr; +		} +	} else { +		if (canvas_item->canvas_group == nullptr) { +			canvas_item->canvas_group = memnew(RasterizerCanvas::Item::CanvasGroup); +		} +		canvas_item->canvas_group->mode = p_mode; +		canvas_item->canvas_group->fit_empty = p_fit_empty; +		canvas_item->canvas_group->fit_margin = p_fit_margin; +		canvas_item->canvas_group->blur_mipmaps = p_blur_mipmaps; +		canvas_item->canvas_group->clear_margin = p_clear_margin; +	} +} +  RID RenderingServerCanvas::canvas_light_create() {  	RasterizerCanvas::Light *clight = memnew(RasterizerCanvas::Light);  	clight->light_internal = RSG::canvas_render->light_create(); diff --git a/servers/rendering/rendering_server_canvas.h b/servers/rendering/rendering_server_canvas.h index 16edfd54e1..8eed6e72d9 100644 --- a/servers/rendering/rendering_server_canvas.h +++ b/servers/rendering/rendering_server_canvas.h @@ -216,6 +216,8 @@ public:  	void canvas_item_set_use_parent_material(RID p_item, bool p_enable); +	void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false); +  	RID canvas_light_create();  	void canvas_light_attach_to_canvas(RID p_light, RID p_canvas);  	void canvas_light_set_enabled(RID p_light, bool p_enabled); diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h index 5744b40321..1c222a48c4 100644 --- a/servers/rendering/rendering_server_raster.h +++ b/servers/rendering/rendering_server_raster.h @@ -743,6 +743,8 @@ public:  	BIND2(canvas_item_set_use_parent_material, RID, bool) +	BIND6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool) +  	BIND0R(RID, canvas_light_create)  	BIND2(canvas_light_attach_to_canvas, RID, RID)  	BIND2(canvas_light_set_enabled, RID, bool) diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h index 1836f99c99..89fd713265 100644 --- a/servers/rendering/rendering_server_wrap_mt.h +++ b/servers/rendering/rendering_server_wrap_mt.h @@ -642,6 +642,8 @@ public:  	FUNC2(canvas_item_set_use_parent_material, RID, bool) +	FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool) +  	FUNC0R(RID, canvas_light_create)  	FUNC2(canvas_light_attach_to_canvas, RID, RID)  	FUNC2(canvas_light_set_enabled, RID, bool) diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 61d0fed52f..a7df1687e0 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1184,6 +1184,14 @@ public:  	virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable) = 0; +	enum CanvasGroupMode { +		CANVAS_GROUP_MODE_DISABLED, +		CANVAS_GROUP_MODE_OPAQUE, +		CANVAS_GROUP_MODE_TRANSPARENT, +	}; + +	virtual void canvas_item_set_canvas_group_mode(RID p_item, CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false) = 0; +  	virtual RID canvas_light_create() = 0;  	virtual void canvas_light_attach_to_canvas(RID p_light, RID p_canvas) = 0;  	virtual void canvas_light_set_enabled(RID p_light, bool p_enabled) = 0; |