Skip to content

Commit

Permalink
Merge pull request #43167 from reduz/canvas-group
Browse files Browse the repository at this point in the history
Implement CanvasGroup and CanvasItem clipping
  • Loading branch information
reduz authored Oct 29, 2020
2 parents 2eaedcf + a65481d commit 50da616
Show file tree
Hide file tree
Showing 20 changed files with 563 additions and 55 deletions.
9 changes: 4 additions & 5 deletions drivers/vulkan/rendering_device_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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;
}
Expand All @@ -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
}

Expand Down
87 changes: 87 additions & 0 deletions scene/2d/canvas_group.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 59 additions & 0 deletions scene/2d/canvas_group.h
Original file line number Diff line number Diff line change
@@ -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
22 changes: 22 additions & 0 deletions scene/main/canvas_item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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", "");
Expand All @@ -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_");
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions scene/main/canvas_item.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ class CanvasItem : public Node {
Window *window;
bool first_draw;
bool visible;
bool clip_children;
bool pending_update;
bool top_level;
bool drawing;
Expand Down Expand Up @@ -315,6 +316,9 @@ class CanvasItem : public Node {

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;

Expand Down
2 changes: 2 additions & 0 deletions scene/register_scene_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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>();
Expand Down
17 changes: 15 additions & 2 deletions scene/resources/dynamic_font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,21 @@ 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;

// Initialize the texture to all-white pixels to prevent artifacts when the
// font is displayed at a non-default scale with filtering enabled.
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);
Expand Down
18 changes: 16 additions & 2 deletions servers/rendering/rasterizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,8 @@ class RasterizerCanvas {
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 {
Expand Down Expand Up @@ -1060,7 +1061,16 @@ class RasterizerCanvas {
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;

Expand All @@ -1084,6 +1094,7 @@ class RasterizerCanvas {
Rect2 final_clip_rect;
Item *final_clip_owner;
Item *material_owner;
Item *canvas_group_owner;
ViewportRender *vp_render;
bool distance_field;
bool light_masked;
Expand Down Expand Up @@ -1242,6 +1253,8 @@ class RasterizerCanvas {
}

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;
Expand Down Expand Up @@ -1282,6 +1295,7 @@ class RasterizerCanvas {
vp_render = nullptr;
next = nullptr;
final_clip_owner = nullptr;
canvas_group_owner = nullptr;
clip = false;
final_modulate = Color(1, 1, 1, 1);
visible = true;
Expand Down
Loading

0 comments on commit 50da616

Please sign in to comment.