Implement CanvasGroup and CanvasItem clipping

-Allows merging several 2D objects into a single draw operation
-Use current node to clip children nodes
-Further fixes to Vulkan barriers
-Changed font texture generation to white, fixes dark eges when blurred
-Other small misc fixes to backbuffer code.
This commit is contained in:
reduz 2020-10-28 15:34:27 -03:00
parent 2eaedcf14e
commit 8ab9b39707
20 changed files with 562 additions and 56 deletions

View File

@ -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
}

87
scene/2d/canvas_group.cpp Normal file
View File

@ -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() {
}

59
scene/2d/canvas_group.h Normal file
View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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>();

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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 *&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);
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);

View File

@ -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(&copy.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(&copy.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, &copy.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(&copy.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, &copy.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, &copy.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");

View File

@ -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);

View File

@ -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());

View File

@ -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);

View File

@ -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
}

View File

@ -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();

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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;