diff options
author | reduz <reduzio@gmail.com> | 2020-10-28 15:34:27 -0300 |
---|---|---|
committer | reduz <reduzio@gmail.com> | 2020-10-28 18:53:32 -0300 |
commit | 8ab9b397070174aab7b20cdcd97506db25fb919d (patch) | |
tree | 521d77e32b056dee703eb96ecbb54ab939f19c6a /servers | |
parent | 2eaedcf14e515eb589885025b46d0aedc492830a (diff) |
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.
Diffstat (limited to 'servers')
-rw-r--r-- | servers/rendering/rasterizer.h | 18 | ||||
-rw-r--r-- | servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp | 113 | ||||
-rw-r--r-- | servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h | 5 | ||||
-rw-r--r-- | servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp | 37 | ||||
-rw-r--r-- | servers/rendering/rasterizer_rd/rasterizer_effects_rd.h | 10 | ||||
-rw-r--r-- | servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp | 91 | ||||
-rw-r--r-- | servers/rendering/rasterizer_rd/rasterizer_storage_rd.h | 6 | ||||
-rw-r--r-- | servers/rendering/rasterizer_rd/shaders/copy.glsl | 28 | ||||
-rw-r--r-- | servers/rendering/rendering_server_canvas.cpp | 96 | ||||
-rw-r--r-- | servers/rendering/rendering_server_canvas.h | 2 | ||||
-rw-r--r-- | servers/rendering/rendering_server_raster.h | 2 | ||||
-rw-r--r-- | servers/rendering/rendering_server_wrap_mt.h | 2 | ||||
-rw-r--r-- | servers/rendering_server.h | 8 |
13 files changed, 370 insertions, 48 deletions
diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h index 4ece811a1e..88b92bd35d 100644 --- a/servers/rendering/rasterizer.h +++ b/servers/rendering/rasterizer.h @@ -815,7 +815,8 @@ public: CANVAS_RECT_FLIP_H = 4, CANVAS_RECT_FLIP_V = 8, CANVAS_RECT_TRANSPOSE = 16, - CANVAS_RECT_CLIP_UV = 32 + CANVAS_RECT_CLIP_UV = 32, + CANVAS_RECT_IS_GROUP = 64, }; struct Light { @@ -1060,7 +1061,16 @@ public: bool visible; bool behind; bool update_when_visible; - //RS::MaterialBlendMode blend_mode; + + struct CanvasGroup { + RS::CanvasGroupMode mode; + bool fit_empty; + float fit_margin; + bool blur_mipmaps; + float clear_margin; + }; + + CanvasGroup *canvas_group = nullptr; int light_mask; int z_final; @@ -1084,6 +1094,7 @@ public: Rect2 final_clip_rect; Item *final_clip_owner; Item *material_owner; + Item *canvas_group_owner; ViewportRender *vp_render; bool distance_field; bool light_masked; @@ -1242,6 +1253,8 @@ public: } void clear() { + // The first one is always allocated on heap + // the rest go in the blocks Command *c = commands; while (c) { Command *n = c->next; @@ -1282,6 +1295,7 @@ public: vp_render = nullptr; next = nullptr; final_clip_owner = nullptr; + canvas_group_owner = nullptr; clip = false; final_modulate = Color(1, 1, 1, 1); visible = true; diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp index 28674b118c..b268db5989 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp @@ -1102,28 +1102,36 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ return uniform_set; } -void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights) { +void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer) { Item *current_clip = nullptr; Transform2D canvas_transform_inverse = p_canvas_transform_inverse; - RID framebuffer = storage->render_target_get_rd_framebuffer(p_to_render_target); - - Vector<Color> clear_colors; + RID framebuffer; + RID fb_uniform_set; bool clear = false; - if (storage->render_target_is_clear_requested(p_to_render_target)) { - clear = true; - clear_colors.push_back(storage->render_target_get_clear_request_color(p_to_render_target)); - storage->render_target_disable_clear_request(p_to_render_target); - } + Vector<Color> clear_colors; + + if (p_to_backbuffer) { + framebuffer = storage->render_target_get_rd_backbuffer_framebuffer(p_to_render_target); + fb_uniform_set = storage->render_target_get_backbuffer_uniform_set(p_to_render_target); + } else { + framebuffer = storage->render_target_get_rd_framebuffer(p_to_render_target); + + if (storage->render_target_is_clear_requested(p_to_render_target)) { + clear = true; + clear_colors.push_back(storage->render_target_get_clear_request_color(p_to_render_target)); + storage->render_target_disable_clear_request(p_to_render_target); + } #ifndef _MSC_VER #warning TODO obtain from framebuffer format eventually when this is implemented #endif - RID fb_uniform_set = storage->render_target_get_framebuffer_uniform_set(p_to_render_target); + fb_uniform_set = storage->render_target_get_framebuffer_uniform_set(p_to_render_target); + } if (fb_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(fb_uniform_set)) { - fb_uniform_set = _create_base_uniform_set(p_to_render_target, false); + fb_uniform_set = _create_base_uniform_set(p_to_render_target, p_to_backbuffer); } RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); @@ -1152,10 +1160,16 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, } } - if (ci->material != prev_material) { + RID material = ci->material; + + if (material.is_null() && ci->canvas_group != nullptr) { + material = default_canvas_group_material; + } + + if (material != prev_material) { MaterialData *material_data = nullptr; - if (ci->material.is_valid()) { - material_data = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D); + if (material.is_valid()) { + material_data = (MaterialData *)storage->material_get_data(material, RasterizerStorageRD::SHADER_TYPE_2D); } if (material_data) { @@ -1174,7 +1188,7 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, _render_item(draw_list, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants); - prev_material = ci->material; + prev_material = material; } RD::get_singleton()->draw_list_end(); @@ -1306,8 +1320,10 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite Rect2 back_buffer_rect; bool backbuffer_copy = false; + Item *canvas_group_owner = nullptr; + while (ci) { - if (ci->copy_back_buffer) { + if (ci->copy_back_buffer && canvas_group_owner == nullptr) { backbuffer_copy = true; if (ci->copy_back_buffer->full) { @@ -1320,7 +1336,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite if (ci->material.is_valid()) { MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D); if (md && md->shader_data->valid) { - if (md->shader_data->uses_screen_texture) { + if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) { if (!material_screen_texture_found) { backbuffer_copy = true; back_buffer_rect = Rect2(); @@ -1338,12 +1354,44 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite } } + if (ci->canvas_group_owner != nullptr) { + if (canvas_group_owner == nullptr) { + //Canvas group begins here, render until before this item + _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list); + item_count = 0; + + Rect2i group_rect = ci->canvas_group_owner->global_rect_cache; + + if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_OPAQUE) { + storage->render_target_copy_to_back_buffer(p_to_render_target, group_rect, false); + } else { + storage->render_target_clear_back_buffer(p_to_render_target, group_rect, Color(0, 0, 0, 0)); + } + + backbuffer_copy = false; + canvas_group_owner = ci->canvas_group_owner; //continue until owner found + } + + ci->canvas_group_owner = nullptr; //must be cleared + } + + if (ci == canvas_group_owner) { + _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, true); + item_count = 0; + + if (ci->canvas_group->blur_mipmaps) { + storage->render_target_gen_back_buffer_mipmaps(p_to_render_target, ci->global_rect_cache); + } + + canvas_group_owner = nullptr; + } + if (backbuffer_copy) { //render anything pending, including clearing if no items _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list); item_count = 0; - storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect); + storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, true); backbuffer_copy = false; material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies @@ -1672,10 +1720,11 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { } break; case BLEND_MODE_MIX: { attachment.enable_blend = true; - attachment.alpha_blend_op = RD::BLEND_OP_ADD; attachment.color_blend_op = RD::BLEND_OP_ADD; attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + + attachment.alpha_blend_op = RD::BLEND_OP_ADD; attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; @@ -2013,6 +2062,20 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { shader.default_version = shader.canvas_shader.version_create(); shader.default_version_rd_shader = shader.canvas_shader.version_get_shader(shader.default_version, SHADER_VARIANT_QUAD); + RD::PipelineColorBlendState blend_state; + RD::PipelineColorBlendState::Attachment blend_attachment; + + blend_attachment.enable_blend = true; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + + blend_state.attachments.push_back(blend_attachment); + for (int i = 0; i < PIPELINE_LIGHT_MODE_MAX; i++) { for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) { RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = { @@ -2054,7 +2117,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { }; RID shader_variant = shader.canvas_shader.version_get_shader(shader.default_version, shader_variants[i][j]); - shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0); + shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0); } } } @@ -2260,6 +2323,13 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { state.time = 0; + { + default_canvas_group_shader = storage->shader_create(); + storage->shader_set_code(default_canvas_group_shader, "shader_type canvas_item; \nvoid fragment() {\n\tvec4 c = textureLod(SCREEN_TEXTURE,SCREEN_UV,0.0); if (c.a > 0.0001) c.rgb/=c.a; COLOR *= c; \n}\n"); + default_canvas_group_material = storage->material_create(); + storage->material_set_shader(default_canvas_group_material, default_canvas_group_shader); + } + static_assert(sizeof(PushConstant) == 128); } @@ -2307,6 +2377,9 @@ void RasterizerCanvasRD::set_shadow_texture_size(int p_size) { RasterizerCanvasRD::~RasterizerCanvasRD() { //canvas state + storage->free(default_canvas_group_material); + storage->free(default_canvas_group_shader); + { if (state.canvas_state_buffer.is_valid()) { RD::get_singleton()->free(state.canvas_state_buffer); diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h index 5791efa4e5..4a79134c24 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h @@ -391,6 +391,9 @@ class RasterizerCanvasRD : public RasterizerCanvas { RID default_canvas_texture; + RID default_canvas_group_shader; + RID default_canvas_group_material; + RS::CanvasItemTextureFilter default_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; RS::CanvasItemTextureRepeat default_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; @@ -398,7 +401,7 @@ class RasterizerCanvasRD : public RasterizerCanvas { inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size); //recursive, so regular inline used instead. void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants); - void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights); + void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer = false); _FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4); _FORCE_INLINE_ void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3); diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp index 409cfdfecf..d669db1b4b 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp @@ -246,7 +246,7 @@ void RasterizerEffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_fr RD::get_singleton()->draw_list_end(); } -void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst) { +void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst, bool p_alpha_to_one) { zeromem(©.push_constant, sizeof(CopyPushConstant)); if (p_flip_y) { copy.push_constant.flags |= COPY_FLAG_FLIP_Y; @@ -260,6 +260,10 @@ void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_textu copy.push_constant.flags |= COPY_FLAG_ALL_SOURCE; } + if (p_alpha_to_one) { + copy.push_constant.flags |= COPY_FLAG_ALPHA_TO_ONE; + } + copy.push_constant.section[0] = 0; copy.push_constant.section[1] = 0; copy.push_constant.section[2] = p_rect.size.width; @@ -354,6 +358,31 @@ void RasterizerEffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest RD::get_singleton()->compute_list_end(); } +void RasterizerEffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst) { + zeromem(©.push_constant, sizeof(CopyPushConstant)); + + copy.push_constant.section[0] = 0; + copy.push_constant.section[1] = 0; + copy.push_constant.section[2] = p_region.size.width; + copy.push_constant.section[3] = p_region.size.height; + copy.push_constant.target[0] = p_region.position.x; + copy.push_constant.target[1] = p_region.position.y; + copy.push_constant.set_color[0] = p_color.r; + copy.push_constant.set_color[1] = p_color.g; + copy.push_constant.set_color[2] = p_color.b; + copy.push_constant.set_color[3] = p_color.a; + + int32_t x_groups = (p_region.size.width - 1) / 8 + 1; + int32_t y_groups = (p_region.size.height - 1) / 8 + 1; + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8bit_dst ? COPY_MODE_SET_COLOR_8BIT : COPY_MODE_SET_COLOR]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); +} + void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) { zeromem(©.push_constant, sizeof(CopyPushConstant)); @@ -369,7 +398,7 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RD::DrawListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8bit_dst ? COPY_MODE_GAUSSIAN_COPY_8BIT : COPY_MODE_GAUSSIAN_COPY]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 3); copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL; RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); @@ -380,7 +409,7 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, //VERTICAL RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_back_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 3); copy.push_constant.flags = base_flags; RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); @@ -1346,6 +1375,8 @@ RasterizerEffectsRD::RasterizerEffectsRD() { copy_modes.push_back("\n#define MODE_SIMPLE_COPY\n"); copy_modes.push_back("\n#define MODE_SIMPLE_COPY\n#define DST_IMAGE_8BIT\n"); copy_modes.push_back("\n#define MODE_SIMPLE_COPY_DEPTH\n"); + copy_modes.push_back("\n#define MODE_SET_COLOR\n"); + copy_modes.push_back("\n#define MODE_SET_COLOR\n#define DST_IMAGE_8BIT\n"); copy_modes.push_back("\n#define MODE_MIPMAP\n"); copy_modes.push_back("\n#define MODE_LINEARIZE_DEPTH_COPY\n"); copy_modes.push_back("\n#define MODE_CUBEMAP_TO_PANORAMA\n"); diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h index 679263fbf6..a0bdd59fd2 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h @@ -66,6 +66,8 @@ class RasterizerEffectsRD { COPY_MODE_SIMPLY_COPY, COPY_MODE_SIMPLY_COPY_8BIT, COPY_MODE_SIMPLY_COPY_DEPTH, + COPY_MODE_SET_COLOR, + COPY_MODE_SET_COLOR_8BIT, COPY_MODE_MIPMAP, COPY_MODE_LINEARIZE_DEPTH, COPY_MODE_CUBE_TO_PANORAMA, @@ -83,7 +85,8 @@ class RasterizerEffectsRD { COPY_FLAG_FLIP_Y = (1 << 5), COPY_FLAG_FORCE_LUMINANCE = (1 << 6), COPY_FLAG_ALL_SOURCE = (1 << 7), - COPY_FLAG_HIGH_QUALITY_GLOW = (1 << 8) + COPY_FLAG_HIGH_QUALITY_GLOW = (1 << 8), + COPY_FLAG_ALPHA_TO_ONE = (1 << 9), }; struct CopyPushConstant { @@ -105,6 +108,8 @@ class RasterizerEffectsRD { float camera_z_far; float camera_z_near; uint32_t pad2[2]; + //SET color + float set_color[4]; }; struct Copy { @@ -603,12 +608,13 @@ class RasterizerEffectsRD { public: void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID()); - void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false); + void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false); void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array); void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false); void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far); void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false); void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false); + void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false); void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0); void cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp index b47d724147..10c9293d67 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp @@ -6131,12 +6131,18 @@ void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { tf.width = rt->size.width; tf.height = rt->size.height; tf.type = RD::TEXTURE_TYPE_2D; - tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; tf.mipmaps = mipmaps_required; rt->backbuffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); rt->backbuffer_mipmap0 = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, 0); + { + Vector<RID> fb_tex; + fb_tex.push_back(rt->backbuffer_mipmap0); + rt->backbuffer_fb = RD::get_singleton()->framebuffer_create(fb_tex); + } + if (rt->framebuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->framebuffer_uniform_set)) { //the new one will require the backbuffer. RD::get_singleton()->free(rt->framebuffer_uniform_set); @@ -6245,6 +6251,17 @@ RID RasterizerStorageRD::render_target_get_rd_backbuffer(RID p_render_target) { return rt->backbuffer; } +RID RasterizerStorageRD::render_target_get_rd_backbuffer_framebuffer(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + if (!rt->backbuffer.is_valid()) { + _create_render_target_backbuffer(rt); + } + + return rt->backbuffer_fb; +} + void RasterizerStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); @@ -6283,21 +6300,30 @@ void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) { rt->clear_requested = false; } -void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region) { +void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); if (!rt->backbuffer.is_valid()) { _create_render_target_backbuffer(rt); } - Rect2i region = p_region; - if (region == Rect2i()) { + Rect2i region; + if (p_region == Rect2i()) { region.size = rt->size; + } else { + region = Rect2i(Size2i(), rt->size).clip(p_region); + if (region.size == Size2i()) { + return; //nothing to do + } } //single texture copy for backbuffer - RD::get_singleton()->texture_copy(rt->color, rt->backbuffer_mipmap0, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true); - //effects.copy(rt->color, rt->backbuffer_fb, blur_region); + //RD::get_singleton()->texture_copy(rt->color, rt->backbuffer_mipmap0, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true); + effects.copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, true, true); + + if (!p_gen_mipmaps) { + return; + } //then mipmap blur RID prev_texture = rt->color; //use color, not backbuffer, as bb has mipmaps. @@ -6314,6 +6340,59 @@ void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, } } +void RasterizerStorageRD::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + if (!rt->backbuffer.is_valid()) { + _create_render_target_backbuffer(rt); + } + + Rect2i region; + if (p_region == Rect2i()) { + region.size = rt->size; + } else { + region = Rect2i(Size2i(), rt->size).clip(p_region); + if (region.size == Size2i()) { + return; //nothing to do + } + } + + //single texture copy for backbuffer + effects.set_color(rt->backbuffer_mipmap0, p_color, region, true); +} + +void RasterizerStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + if (!rt->backbuffer.is_valid()) { + _create_render_target_backbuffer(rt); + } + + Rect2i region; + if (p_region == Rect2i()) { + region.size = rt->size; + } else { + region = Rect2i(Size2i(), rt->size).clip(p_region); + if (region.size == Size2i()) { + return; //nothing to do + } + } + + //then mipmap blur + RID prev_texture = rt->backbuffer_mipmap0; + + for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) { + region.position.x >>= 1; + region.position.y >>= 1; + region.size.x = MAX(1, region.size.x >> 1); + region.size.y = MAX(1, region.size.y >> 1); + + const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i]; + effects.gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true); + prev_texture = mm.mipmap; + } +} + RID RasterizerStorageRD::render_target_get_framebuffer_uniform_set(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h index 7caafca2e0..321bff9fdd 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h @@ -989,6 +989,7 @@ private: bool flags[RENDER_TARGET_FLAG_MAX]; RID backbuffer; //used for effects + RID backbuffer_fb; RID backbuffer_mipmap0; struct BackbufferMipmap { @@ -1916,7 +1917,9 @@ public: void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value); bool render_target_was_used(RID p_render_target); void render_target_set_as_unused(RID p_render_target); - void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region); + void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps); + void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color); + void render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region); RID render_target_get_back_buffer_uniform_set(RID p_render_target, RID p_base_shader); @@ -1930,6 +1933,7 @@ public: RID render_target_get_rd_framebuffer(RID p_render_target); RID render_target_get_rd_texture(RID p_render_target); RID render_target_get_rd_backbuffer(RID p_render_target); + RID render_target_get_rd_backbuffer_framebuffer(RID p_render_target); RID render_target_get_framebuffer_uniform_set(RID p_render_target); RID render_target_get_backbuffer_uniform_set(RID p_render_target); diff --git a/servers/rendering/rasterizer_rd/shaders/copy.glsl b/servers/rendering/rasterizer_rd/shaders/copy.glsl index 355a2b9d75..cdd35dfb3f 100644 --- a/servers/rendering/rasterizer_rd/shaders/copy.glsl +++ b/servers/rendering/rasterizer_rd/shaders/copy.glsl @@ -15,6 +15,7 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; #define FLAG_FORCE_LUMINANCE (1 << 6) #define FLAG_COPY_ALL_SOURCE (1 << 7) #define FLAG_HIGH_QUALITY_GLOW (1 << 8) +#define FLAG_ALPHA_TO_ONE (1 << 9) layout(push_constant, binding = 1, std430) uniform Params { ivec4 section; @@ -35,6 +36,8 @@ layout(push_constant, binding = 1, std430) uniform Params { float camera_z_far; float camera_z_near; uint pad2[2]; + + vec4 set_color; } params; @@ -42,7 +45,7 @@ params; layout(set = 0, binding = 0) uniform samplerCubeArray source_color; #elif defined(MODE_CUBEMAP_TO_PANORAMA) layout(set = 0, binding = 0) uniform samplerCube source_color; -#else +#elif !defined(MODE_SET_COLOR) layout(set = 0, binding = 0) uniform sampler2D source_color; #endif @@ -203,25 +206,24 @@ void main() { } color = textureLod(source_color, uv, 0.0); - if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { - color.rgb = vec3(max(max(color.r, color.g), color.b)); - } - imageStore(dest_buffer, pos + params.target, color); - } else { color = texelFetch(source_color, pos + params.section.xy, 0); - if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { - color.rgb = vec3(max(max(color.r, color.g), color.b)); - } - if (bool(params.flags & FLAG_FLIP_Y)) { pos.y = params.section.w - pos.y - 1; } + } - imageStore(dest_buffer, pos + params.target, color); + if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { + color.rgb = vec3(max(max(color.r, color.g), color.b)); + } + + if (bool(params.flags & FLAG_ALPHA_TO_ONE)) { + color.a = 1.0; } + imageStore(dest_buffer, pos + params.target, color); + #endif #ifdef MODE_SIMPLE_COPY_DEPTH @@ -270,4 +272,8 @@ void main() { #endif imageStore(dest_buffer, pos + params.target, color); #endif + +#ifdef MODE_SET_COLOR + imageStore(dest_buffer, pos + params.target, params.set_color); +#endif } diff --git a/servers/rendering/rendering_server_canvas.cpp b/servers/rendering/rendering_server_canvas.cpp index b0bff8b2c2..f06667a460 100644 --- a/servers/rendering/rendering_server_canvas.cpp +++ b/servers/rendering/rendering_server_canvas.cpp @@ -167,8 +167,15 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo p_z = ci->z_index; } + RasterizerCanvas::Item *canvas_group_from = nullptr; + bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr); + if (use_canvas_group) { + int zidx = p_z - RS::CANVAS_ITEM_Z_MIN; + canvas_group_from = z_last_list[zidx]; + } + for (int i = 0; i < child_item_count; i++) { - if (!child_items[i]->behind || (ci->sort_y && child_items[i]->sort_y)) { + if ((!child_items[i]->behind && !use_canvas_group) || (ci->sort_y && child_items[i]->sort_y)) { continue; } if (ci->sort_y) { @@ -182,6 +189,70 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).clip(p_clip_rect); } + if (use_canvas_group) { + int zidx = p_z - RS::CANVAS_ITEM_Z_MIN; + if (canvas_group_from == nullptr) { + // no list before processing this item, means must put stuff in group from the beginning of list. + canvas_group_from = z_list[zidx]; + } else { + // there was a list before processing, so begin group from this one. + canvas_group_from = canvas_group_from->next; + } + + if (canvas_group_from) { + // Has a place to begin the group from! + + //compute a global rect (in global coords) for children in the same z layer + Rect2 rect_accum; + RasterizerCanvas::Item *c = canvas_group_from; + while (c) { + if (c == canvas_group_from) { + rect_accum = c->global_rect_cache; + } else { + rect_accum = rect_accum.merge(c->global_rect_cache); + } + + c = c->next; + } + + // We have two choices now, if user has drawn something, we must assume users wants to draw the "mask", so compute the size based on this. + // If nothing has been drawn, we just take it over and draw it ourselves. + if (ci->canvas_group->fit_empty && (ci->commands == nullptr || + (ci->commands->next == nullptr && ci->commands->type == Item::Command::TYPE_RECT && (static_cast<Item::CommandRect *>(ci->commands)->flags & RasterizerCanvas::CANVAS_RECT_IS_GROUP)))) { + // No commands, or sole command is the one used to draw, so we (re)create the draw command. + ci->clear(); + + if (rect_accum == Rect2()) { + rect_accum.size = Size2(1, 1); + } + + rect_accum = rect_accum.grow(ci->canvas_group->fit_margin); + + //draw it? + RasterizerCanvas::Item::CommandRect *crect = ci->alloc_command<RasterizerCanvas::Item::CommandRect>(); + + crect->flags = RasterizerCanvas::CANVAS_RECT_IS_GROUP; // so we can recognize it later + crect->rect = xform.affine_inverse().xform(rect_accum); + crect->modulate = Color(1, 1, 1, 1); + + //the global rect is used to do the copying, so update it + global_rect = rect_accum.grow(ci->canvas_group->clear_margin); //grow again by clear margin + global_rect.position += p_clip_rect.position; + } else { + global_rect.position -= p_clip_rect.position; + + global_rect = global_rect.merge(rect_accum); //must use both rects for this + global_rect = global_rect.grow(ci->canvas_group->clear_margin); //grow by clear margin + + global_rect.position += p_clip_rect.position; + } + + // Very important that this is cleared after used in RasterizerCanvas to avoid + // potential crashes. + canvas_group_from->canvas_group_owner = ci; + } + } + if (ci->update_when_visible) { RenderingServerRaster::redraw_request(); } @@ -211,7 +282,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo } for (int i = 0; i < child_item_count; i++) { - if (child_items[i]->behind || (ci->sort_y && child_items[i]->sort_y)) { + if (child_items[i]->behind || use_canvas_group || (ci->sort_y && child_items[i]->sort_y)) { continue; } if (ci->sort_y) { @@ -935,6 +1006,27 @@ void RenderingServerCanvas::canvas_item_set_use_parent_material(RID p_item, bool canvas_item->use_parent_material = p_enable; } +void RenderingServerCanvas::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) { + Item *canvas_item = canvas_item_owner.getornull(p_item); + ERR_FAIL_COND(!canvas_item); + + if (p_mode == RS::CANVAS_GROUP_MODE_DISABLED) { + if (canvas_item->canvas_group != nullptr) { + memdelete(canvas_item->canvas_group); + canvas_item->canvas_group = nullptr; + } + } else { + if (canvas_item->canvas_group == nullptr) { + canvas_item->canvas_group = memnew(RasterizerCanvas::Item::CanvasGroup); + } + canvas_item->canvas_group->mode = p_mode; + canvas_item->canvas_group->fit_empty = p_fit_empty; + canvas_item->canvas_group->fit_margin = p_fit_margin; + canvas_item->canvas_group->blur_mipmaps = p_blur_mipmaps; + canvas_item->canvas_group->clear_margin = p_clear_margin; + } +} + RID RenderingServerCanvas::canvas_light_create() { RasterizerCanvas::Light *clight = memnew(RasterizerCanvas::Light); clight->light_internal = RSG::canvas_render->light_create(); diff --git a/servers/rendering/rendering_server_canvas.h b/servers/rendering/rendering_server_canvas.h index 16edfd54e1..8eed6e72d9 100644 --- a/servers/rendering/rendering_server_canvas.h +++ b/servers/rendering/rendering_server_canvas.h @@ -216,6 +216,8 @@ public: void canvas_item_set_use_parent_material(RID p_item, bool p_enable); + void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false); + RID canvas_light_create(); void canvas_light_attach_to_canvas(RID p_light, RID p_canvas); void canvas_light_set_enabled(RID p_light, bool p_enabled); diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h index 5744b40321..1c222a48c4 100644 --- a/servers/rendering/rendering_server_raster.h +++ b/servers/rendering/rendering_server_raster.h @@ -743,6 +743,8 @@ public: BIND2(canvas_item_set_use_parent_material, RID, bool) + BIND6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool) + BIND0R(RID, canvas_light_create) BIND2(canvas_light_attach_to_canvas, RID, RID) BIND2(canvas_light_set_enabled, RID, bool) diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h index 1836f99c99..89fd713265 100644 --- a/servers/rendering/rendering_server_wrap_mt.h +++ b/servers/rendering/rendering_server_wrap_mt.h @@ -642,6 +642,8 @@ public: FUNC2(canvas_item_set_use_parent_material, RID, bool) + FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool) + FUNC0R(RID, canvas_light_create) FUNC2(canvas_light_attach_to_canvas, RID, RID) FUNC2(canvas_light_set_enabled, RID, bool) diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 61d0fed52f..a7df1687e0 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1184,6 +1184,14 @@ public: virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable) = 0; + enum CanvasGroupMode { + CANVAS_GROUP_MODE_DISABLED, + CANVAS_GROUP_MODE_OPAQUE, + CANVAS_GROUP_MODE_TRANSPARENT, + }; + + virtual void canvas_item_set_canvas_group_mode(RID p_item, CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false) = 0; + virtual RID canvas_light_create() = 0; virtual void canvas_light_attach_to_canvas(RID p_light, RID p_canvas) = 0; virtual void canvas_light_set_enabled(RID p_light, bool p_enabled) = 0; |