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:
parent
2eaedcf14e
commit
8ab9b39707
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue