diff options
Diffstat (limited to 'servers/rendering')
14 files changed, 505 insertions, 112 deletions
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index e48c72cec7..42de831e7a 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -38,6 +38,12 @@ #include "rendering_server_globals.h" #include "servers/rendering/storage/texture_storage.h" +// Use the same antialiasing feather size as StyleBoxFlat's default +// (but doubled, as it's specified for both sides here). +// This value is empirically determined to provide good antialiasing quality +// while not making lines appear too soft. +const static float FEATHER_SIZE = 1.25f; + void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info) { RENDER_TIMESTAMP("Cull CanvasItem Tree"); @@ -638,11 +644,8 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, } if (p_antialiased) { - // Use the same antialiasing feather size as StyleBoxFlat's default - // (but doubled, as it's specified for both sides here). - // This value is empirically determined to provide good antialiasing quality - // while not making lines appear too soft. - float border_size = 1.25f; + float border_size = FEATHER_SIZE; + if (0.0f <= p_width && p_width < 1.0f) { border_size *= p_width; } @@ -651,7 +654,7 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, Vector2 border = dir * border_size; Vector2 border2 = dir2 * border_size; - Color transparent = Color(p_color.r, p_color.g, p_color.b, 0.0); + Color transparent = Color(p_color, 0.0); { Item::CommandPrimitive *left_border = canvas_item->alloc_command<Item::CommandPrimitive>(); @@ -903,11 +906,7 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point Color *colors_ptr = colors.ptrw(); if (p_antialiased) { - // Use the same antialiasing feather size as StyleBoxFlat's default - // (but doubled, as it's specified for both sides here). - // This value is empirically determined to provide good antialiasing quality - // while not making lines appear too soft. - float border_size = 1.25f; + float border_size = FEATHER_SIZE; if (p_width < 1.0f) { border_size *= p_width; } @@ -1094,12 +1093,15 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point pline->polygon.create(indices, points, colors); } -void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) { +void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) { ERR_FAIL_COND(p_points.is_empty() || p_points.size() % 2 != 0); ERR_FAIL_COND(p_colors.size() != 1 && p_colors.size() * 2 != p_points.size()); // TODO: `canvas_item_add_line`(`multiline`, `polyline`) share logic, should factor out. if (p_width < 0) { + if (p_antialiased) { + WARN_PRINT("Antialiasing is not supported for thin multilines drawn using line strips (`p_width < 0`)."); + } Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_NULL(canvas_item); @@ -1127,7 +1129,7 @@ void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Poin Vector2 from = p_points[i * 2 + 0]; Vector2 to = p_points[i * 2 + 1]; - canvas_item_add_line(p_item, from, to, color, p_width); + canvas_item_add_line(p_item, from, to, color, p_width, p_antialiased); } } else { //} else if (p_colors.size() << 1 == p_points.size()) { for (int i = 0; i < p_colors.size(); i++) { @@ -1135,13 +1137,13 @@ void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Poin Vector2 from = p_points[i * 2 + 0]; Vector2 to = p_points[i * 2 + 1]; - canvas_item_add_line(p_item, from, to, color, p_width); + canvas_item_add_line(p_item, from, to, color, p_width, p_antialiased); } } } } -void RendererCanvasCull::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) { +void RendererCanvasCull::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color, bool p_antialiased) { Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_NULL(canvas_item); @@ -1149,45 +1151,251 @@ void RendererCanvasCull::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, c ERR_FAIL_NULL(rect); rect->modulate = p_color; rect->rect = p_rect; + + // Add feathers. + if (p_antialiased) { + float border_size = FEATHER_SIZE; + + const real_t size = MIN(p_rect.size.width, p_rect.size.height); + if (0.0f <= size && size < 1.0f) { + border_size *= size; + } + + const Vector2 vec_down = Vector2(0.0f, p_rect.size.height); + const Vector2 vec_right = Vector2(p_rect.size.width, 0.0f); + + const Vector2 begin_left = p_rect.position; + const Vector2 begin_right = p_rect.position + vec_down; + const Vector2 end_left = p_rect.position + vec_right; + const Vector2 end_right = p_rect.position + p_rect.size; + + const Vector2 dir = Vector2(0.0f, -1.0f); + const Vector2 dir2 = Vector2(-1.0f, 0.0f); + const Vector2 border = dir * border_size; + const Vector2 border2 = dir2 * border_size; + + Color transparent = Color(p_color, 0.0); + + { + Item::CommandPrimitive *left_border = canvas_item->alloc_command<Item::CommandPrimitive>(); + ERR_FAIL_NULL(left_border); + + left_border->points[0] = begin_left; + left_border->points[1] = begin_left + border; + left_border->points[2] = end_left + border; + left_border->points[3] = end_left; + + left_border->colors[0] = p_color; + left_border->colors[1] = transparent; + left_border->colors[2] = transparent; + left_border->colors[3] = p_color; + + left_border->point_count = 4; + } + { + Item::CommandPrimitive *right_border = canvas_item->alloc_command<Item::CommandPrimitive>(); + ERR_FAIL_NULL(right_border); + + right_border->points[0] = begin_right; + right_border->points[1] = begin_right - border; + right_border->points[2] = end_right - border; + right_border->points[3] = end_right; + + right_border->colors[0] = p_color; + right_border->colors[1] = transparent; + right_border->colors[2] = transparent; + right_border->colors[3] = p_color; + + right_border->point_count = 4; + } + { + Item::CommandPrimitive *top_border = canvas_item->alloc_command<Item::CommandPrimitive>(); + ERR_FAIL_NULL(top_border); + + top_border->points[0] = begin_left; + top_border->points[1] = begin_left + border2; + top_border->points[2] = begin_right + border2; + top_border->points[3] = begin_right; + + top_border->colors[0] = p_color; + top_border->colors[1] = transparent; + top_border->colors[2] = transparent; + top_border->colors[3] = p_color; + + top_border->point_count = 4; + } + { + Item::CommandPrimitive *bottom_border = canvas_item->alloc_command<Item::CommandPrimitive>(); + ERR_FAIL_NULL(bottom_border); + + bottom_border->points[0] = end_left; + bottom_border->points[1] = end_left - border2; + bottom_border->points[2] = end_right - border2; + bottom_border->points[3] = end_right; + + bottom_border->colors[0] = p_color; + bottom_border->colors[1] = transparent; + bottom_border->colors[2] = transparent; + bottom_border->colors[3] = p_color; + + bottom_border->point_count = 4; + } + { + Item::CommandPrimitive *top_left_corner = canvas_item->alloc_command<Item::CommandPrimitive>(); + ERR_FAIL_NULL(top_left_corner); + + top_left_corner->points[0] = begin_left; + top_left_corner->points[1] = begin_left + border2; + top_left_corner->points[2] = begin_left + border + border2; + top_left_corner->points[3] = begin_left + border; + + top_left_corner->colors[0] = p_color; + top_left_corner->colors[1] = transparent; + top_left_corner->colors[2] = transparent; + top_left_corner->colors[3] = transparent; + + top_left_corner->point_count = 4; + } + { + Item::CommandPrimitive *top_right_corner = canvas_item->alloc_command<Item::CommandPrimitive>(); + ERR_FAIL_NULL(top_right_corner); + + top_right_corner->points[0] = begin_right; + top_right_corner->points[1] = begin_right + border2; + top_right_corner->points[2] = begin_right - border + border2; + top_right_corner->points[3] = begin_right - border; + + top_right_corner->colors[0] = p_color; + top_right_corner->colors[1] = transparent; + top_right_corner->colors[2] = transparent; + top_right_corner->colors[3] = transparent; + + top_right_corner->point_count = 4; + } + { + Item::CommandPrimitive *bottom_left_corner = canvas_item->alloc_command<Item::CommandPrimitive>(); + ERR_FAIL_NULL(bottom_left_corner); + + bottom_left_corner->points[0] = end_left; + bottom_left_corner->points[1] = end_left - border2; + bottom_left_corner->points[2] = end_left + border - border2; + bottom_left_corner->points[3] = end_left + border; + + bottom_left_corner->colors[0] = p_color; + bottom_left_corner->colors[1] = transparent; + bottom_left_corner->colors[2] = transparent; + bottom_left_corner->colors[3] = transparent; + + bottom_left_corner->point_count = 4; + } + { + Item::CommandPrimitive *bottom_right_corner = canvas_item->alloc_command<Item::CommandPrimitive>(); + ERR_FAIL_NULL(bottom_right_corner); + + bottom_right_corner->points[0] = end_right; + bottom_right_corner->points[1] = end_right - border2; + bottom_right_corner->points[2] = end_right - border - border2; + bottom_right_corner->points[3] = end_right - border; + + bottom_right_corner->colors[0] = p_color; + bottom_right_corner->colors[1] = transparent; + bottom_right_corner->colors[2] = transparent; + bottom_right_corner->colors[3] = transparent; + + bottom_right_corner->point_count = 4; + } + } } -void RendererCanvasCull::canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) { +void RendererCanvasCull::canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color, bool p_antialiased) { Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_NULL(canvas_item); - Item::CommandPolygon *circle = canvas_item->alloc_command<Item::CommandPolygon>(); - ERR_FAIL_NULL(circle); + static const int circle_segments = 64; - circle->primitive = RS::PRIMITIVE_TRIANGLES; + { + Item::CommandPolygon *circle = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_NULL(circle); - Vector<int> indices; - Vector<Vector2> points; + circle->primitive = RS::PRIMITIVE_TRIANGLES; - static const int circle_points = 64; + Vector<int> indices; + Vector<Vector2> points; - points.resize(circle_points); - Vector2 *points_ptr = points.ptrw(); - const real_t circle_point_step = Math_TAU / circle_points; + points.resize(circle_segments + 2); + Vector2 *points_ptr = points.ptrw(); - for (int i = 0; i < circle_points; i++) { - float angle = i * circle_point_step; - points_ptr[i].x = Math::cos(angle) * p_radius; - points_ptr[i].y = Math::sin(angle) * p_radius; - points_ptr[i] += p_pos; - } + // Store circle center in the last point. + points_ptr[circle_segments + 1] = p_pos; - indices.resize((circle_points - 2) * 3); - int *indices_ptr = indices.ptrw(); + const real_t circle_point_step = Math_TAU / circle_segments; + + for (int i = 0; i < circle_segments + 1; i++) { + float angle = i * circle_point_step; + points_ptr[i].x = Math::cos(angle) * p_radius; + points_ptr[i].y = Math::sin(angle) * p_radius; + points_ptr[i] += p_pos; + } - for (int i = 0; i < circle_points - 2; i++) { - indices_ptr[i * 3 + 0] = 0; - indices_ptr[i * 3 + 1] = i + 1; - indices_ptr[i * 3 + 2] = i + 2; + indices.resize(circle_segments * 3); + int *indices_ptr = indices.ptrw(); + + for (int i = 0; i < circle_segments; i++) { + indices_ptr[i * 3 + 0] = circle_segments + 1; + indices_ptr[i * 3 + 1] = i; + indices_ptr[i * 3 + 2] = i + 1; + } + + Vector<Color> color; + color.push_back(p_color); + circle->polygon.create(indices, points, color); } - Vector<Color> color; - color.push_back(p_color); - circle->polygon.create(indices, points, color); + if (p_antialiased) { + float border_size = FEATHER_SIZE; + + const float diameter = p_radius * 2.0f; + if (0.0f <= diameter && diameter < 1.0f) { + border_size *= p_radius; + } + + Item::CommandPolygon *feather = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_NULL(feather); + feather->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + + Color transparent = Color(p_color, 0.0); + + Vector<int> indices; + Vector<Color> colors; + Vector<Vector2> points; + + points.resize(2 * circle_segments + 2); + colors.resize(2 * circle_segments + 2); + + const real_t circle_point_step = Math_TAU / circle_segments; + + Vector2 *points_ptr = points.ptrw(); + Color *colors_ptr = colors.ptrw(); + + for (int i = 0; i < circle_segments + 1; i++) { + const float angle = i * circle_point_step; + const float c = Math::cos(angle); + const float s = Math::sin(angle); + + points_ptr[i * 2].x = c * p_radius; + points_ptr[i * 2].y = s * p_radius; + points_ptr[i * 2] += p_pos; + + points_ptr[i * 2 + 1].x = c * (p_radius + border_size); + points_ptr[i * 2 + 1].y = s * (p_radius + border_size); + points_ptr[i * 2 + 1] += p_pos; + + colors_ptr[i * 2] = p_color; + colors_ptr[i * 2 + 1] = transparent; + } + + feather->polygon.create(indices, points, colors); + } } void RendererCanvasCull::canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile, const Color &p_modulate, bool p_transpose) { diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index 961506ca28..9f8cbea2e9 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -233,9 +233,9 @@ public: void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = -1.0, bool p_antialiased = false); void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0, bool p_antialiased = false); - void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0); - void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color); - void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color); + void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0, bool p_antialiased = false); + void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color, bool p_antialiased); + void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color, bool p_antialiased); void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false); void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false); void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0, float p_scale = 1.0); diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 8175010caf..068f9d9ef2 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1812,6 +1812,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RS::EnvironmentBG bg_mode = environment_get_background(p_render_data->environment); float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment); bg_energy_multiplier *= environment_get_bg_intensity(p_render_data->environment); + RS::EnvironmentReflectionSource reflection_source = environment_get_reflection_source(p_render_data->environment); if (p_render_data->camera_attributes.is_valid()) { bg_energy_multiplier *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); @@ -1823,7 +1824,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co clear_color.r *= bg_energy_multiplier; clear_color.g *= bg_energy_multiplier; clear_color.b *= bg_energy_multiplier; - if ((rb->has_custom_data(RB_SCOPE_FOG)) || environment_get_fog_enabled(p_render_data->environment)) { + if (!p_render_data->transparent_bg && rb->has_custom_data(RB_SCOPE_FOG) && environment_get_fog_enabled(p_render_data->environment)) { draw_sky_fog_only = true; RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear())); } @@ -1833,13 +1834,13 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co clear_color.r *= bg_energy_multiplier; clear_color.g *= bg_energy_multiplier; clear_color.b *= bg_energy_multiplier; - if ((rb->has_custom_data(RB_SCOPE_FOG)) || environment_get_fog_enabled(p_render_data->environment)) { + if (!p_render_data->transparent_bg && rb->has_custom_data(RB_SCOPE_FOG) && environment_get_fog_enabled(p_render_data->environment)) { draw_sky_fog_only = true; RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear())); } } break; case RS::ENV_BG_SKY: { - draw_sky = true; + draw_sky = !p_render_data->transparent_bg; } break; case RS::ENV_BG_CANVAS: { if (!is_reflection_probe) { @@ -1859,7 +1860,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } // setup sky if used for ambient, reflections, or background - if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) { + if (draw_sky || draw_sky_fog_only || (reflection_source == RS::ENV_REFLECTION_SOURCE_BG && bg_mode == RS::ENV_BG_SKY) || reflection_source == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) { RENDER_TIMESTAMP("Setup Sky"); RD::get_singleton()->draw_command_begin_label("Setup Sky"); @@ -3578,11 +3579,11 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te RID RenderForwardClustered::_render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) { Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED); - return p_render_buffers->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED ? rb_data->get_normal_roughness() : rb_data->get_normal_roughness_msaa(); + return rb_data->get_normal_roughness(); } RID RenderForwardClustered::_render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) { - return p_render_buffers->get_velocity_buffer(p_render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED); + return p_render_buffers->get_velocity_buffer(false); } void RenderForwardClustered::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 5715d94d95..878ea7bcfb 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -830,6 +830,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RS::EnvironmentBG bg_mode = environment_get_background(p_render_data->environment); float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment); bg_energy_multiplier *= environment_get_bg_intensity(p_render_data->environment); + RS::EnvironmentReflectionSource reflection_source = environment_get_reflection_source(p_render_data->environment); if (p_render_data->camera_attributes.is_valid()) { bg_energy_multiplier *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); @@ -841,7 +842,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color clear_color.r *= bg_energy_multiplier; clear_color.g *= bg_energy_multiplier; clear_color.b *= bg_energy_multiplier; - if (environment_get_fog_enabled(p_render_data->environment)) { + if (!p_render_data->transparent_bg && environment_get_fog_enabled(p_render_data->environment)) { draw_sky_fog_only = true; RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear())); } @@ -851,13 +852,13 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color clear_color.r *= bg_energy_multiplier; clear_color.g *= bg_energy_multiplier; clear_color.b *= bg_energy_multiplier; - if (environment_get_fog_enabled(p_render_data->environment)) { + if (!p_render_data->transparent_bg && environment_get_fog_enabled(p_render_data->environment)) { draw_sky_fog_only = true; RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear())); } } break; case RS::ENV_BG_SKY: { - draw_sky = true; + draw_sky = !p_render_data->transparent_bg; } break; case RS::ENV_BG_CANVAS: { if (rb_data.is_valid()) { @@ -874,7 +875,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color } // setup sky if used for ambient, reflections, or background - if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) { + if (draw_sky || draw_sky_fog_only || (reflection_source == RS::ENV_REFLECTION_SOURCE_BG && bg_mode == RS::ENV_BG_SKY) || reflection_source == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) { RENDER_TIMESTAMP("Setup Sky"); RD::get_singleton()->draw_command_begin_label("Setup Sky"); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 012451a5cd..14d138181f 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -169,7 +169,11 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color return; } - RD::get_singleton()->screen_prepare_for_drawing(DisplayServer::MAIN_WINDOW_ID); + Error err = RD::get_singleton()->screen_prepare_for_drawing(DisplayServer::MAIN_WINDOW_ID); + if (err != OK) { + // Window is minimized and does not have valid swapchain, skip drawing without printing errors. + return; + } RID texture = texture_storage->texture_allocate(); texture_storage->texture_2d_initialize(texture, p_image); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 6cb03871c9..1e4880e67a 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1149,6 +1149,10 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render render_data.sdfgi_update_data = p_sdfgi_update_data; render_data.render_info = r_render_info; + + if (p_render_buffers.is_valid() && p_reflection_probe.is_null()) { + render_data.transparent_bg = texture_storage->render_target_get_transparent(rb->get_render_target()); + } } PagedArray<RID> empty; diff --git a/servers/rendering/renderer_rd/storage_rd/render_data_rd.h b/servers/rendering/renderer_rd/storage_rd/render_data_rd.h index 2f61899a18..3cd397b8ed 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_data_rd.h +++ b/servers/rendering/renderer_rd/storage_rd/render_data_rd.h @@ -78,6 +78,9 @@ public: RenderingMethod::RenderInfo *render_info = nullptr; + /* Viewport data */ + bool transparent_bg = false; + /* Shadow data */ const RendererSceneRender::RenderShadowData *render_shadows = nullptr; int render_shadow_count = 0; diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index f844919df1..6e5e8f63e0 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -1457,6 +1457,23 @@ void TextureStorage::texture_set_detect_roughness_callback(RID p_texture, RS::Te } void TextureStorage::texture_debug_usage(List<RS::TextureInfo> *r_info) { + List<RID> textures; + texture_owner.get_owned_list(&textures); + + for (List<RID>::Element *E = textures.front(); E; E = E->next()) { + Texture *t = texture_owner.get_or_null(E->get()); + if (!t) { + continue; + } + RS::TextureInfo tinfo; + tinfo.path = t->path; + tinfo.format = t->format; + tinfo.width = t->width; + tinfo.height = t->height; + tinfo.depth = t->depth; + tinfo.bytes = Image::get_image_data_size(t->width, t->height, t->format, t->mipmaps); + r_info->push_back(tinfo); + } } void TextureStorage::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) { @@ -3042,6 +3059,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { texture_2d_placeholder_initialize(rt->texture); Texture *tex = get_texture(rt->texture); tex->is_render_target = true; + tex->path = "Render Target (Internal)"; } _clear_render_target(rt); diff --git a/servers/rendering/rendering_context_driver.h b/servers/rendering/rendering_context_driver.h index df1424da95..539b3814a0 100644 --- a/servers/rendering/rendering_context_driver.h +++ b/servers/rendering/rendering_context_driver.h @@ -73,10 +73,15 @@ public: DEVICE_TYPE_MAX = 0x5 }; + struct Workarounds { + bool avoid_compute_after_draw = false; + }; + struct Device { String name = "Unknown"; Vendor vendor = VENDOR_UNKNOWN; DeviceType type = DEVICE_TYPE_OTHER; + Workarounds workarounds; }; virtual ~RenderingContextDriver(); diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 31fc51efaa..15e1731823 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -3154,9 +3154,6 @@ Error RenderingDevice::screen_create(DisplayServer::WindowID p_screen) { RDD::SwapChainID swap_chain = driver->swap_chain_create(surface); ERR_FAIL_COND_V_MSG(swap_chain.id == 0, ERR_CANT_CREATE, "Unable to create swap chain."); - Error err = driver->swap_chain_resize(main_queue, swap_chain, _get_swap_chain_desired_count()); - ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_CREATE, "Unable to resize the new swap chain."); - screen_swap_chains[p_screen] = swap_chain; return OK; @@ -3774,13 +3771,13 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint #endif - // Bind descriptor sets. - +#ifdef DEBUG_ENABLED for (uint32_t i = 0; i < dl->state.set_count; i++) { if (dl->state.sets[i].pipeline_expected_format == 0) { - continue; // Nothing expected by this pipeline. + // Nothing expected by this pipeline. + continue; } -#ifdef DEBUG_ENABLED + if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) { if (dl->state.sets[i].uniform_set_format == 0) { ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline."); @@ -3791,9 +3788,22 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader)); } } + } #endif - draw_graph.add_draw_list_uniform_set_prepare_for_use(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i); + + // Prepare descriptor sets if the API doesn't use pipeline barriers. + if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { + for (uint32_t i = 0; i < dl->state.set_count; i++) { + if (dl->state.sets[i].pipeline_expected_format == 0) { + // Nothing expected by this pipeline. + continue; + } + + draw_graph.add_draw_list_uniform_set_prepare_for_use(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i); + } } + + // Bind descriptor sets. for (uint32_t i = 0; i < dl->state.set_count; i++) { if (dl->state.sets[i].pipeline_expected_format == 0) { continue; // Nothing expected by this pipeline. @@ -4167,13 +4177,13 @@ void RenderingDevice::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_g #endif - // Bind descriptor sets. - +#ifdef DEBUG_ENABLED for (uint32_t i = 0; i < cl->state.set_count; i++) { if (cl->state.sets[i].pipeline_expected_format == 0) { - continue; // Nothing expected by this pipeline. + // Nothing expected by this pipeline. + continue; } -#ifdef DEBUG_ENABLED + if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) { if (cl->state.sets[i].uniform_set_format == 0) { ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline."); @@ -4184,9 +4194,22 @@ void RenderingDevice::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_g ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader)); } } + } #endif - draw_graph.add_compute_list_uniform_set_prepare_for_use(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i); + + // Prepare descriptor sets if the API doesn't use pipeline barriers. + if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { + for (uint32_t i = 0; i < cl->state.set_count; i++) { + if (cl->state.sets[i].pipeline_expected_format == 0) { + // Nothing expected by this pipeline. + continue; + } + + draw_graph.add_compute_list_uniform_set_prepare_for_use(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i); + } } + + // Bind descriptor sets. for (uint32_t i = 0; i < cl->state.set_count; i++) { if (cl->state.sets[i].pipeline_expected_format == 0) { continue; // Nothing expected by this pipeline. @@ -4261,16 +4284,16 @@ void RenderingDevice::compute_list_dispatch_indirect(ComputeListID p_list, RID p #endif - // Bind descriptor sets. - +#ifdef DEBUG_ENABLED for (uint32_t i = 0; i < cl->state.set_count; i++) { if (cl->state.sets[i].pipeline_expected_format == 0) { - continue; // Nothing expected by this pipeline. + // Nothing expected by this pipeline. + continue; } -#ifdef DEBUG_ENABLED + if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) { if (cl->state.sets[i].uniform_set_format == 0) { - ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline"); + ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline."); } else if (uniform_set_owner.owns(cl->state.sets[i].uniform_set)) { UniformSet *us = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set); ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader)); @@ -4278,9 +4301,22 @@ void RenderingDevice::compute_list_dispatch_indirect(ComputeListID p_list, RID p ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader)); } } + } #endif - draw_graph.add_compute_list_uniform_set_prepare_for_use(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i); + + // Prepare descriptor sets if the API doesn't use pipeline barriers. + if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { + for (uint32_t i = 0; i < cl->state.set_count; i++) { + if (cl->state.sets[i].pipeline_expected_format == 0) { + // Nothing expected by this pipeline. + continue; + } + + draw_graph.add_compute_list_uniform_set_prepare_for_use(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i); + } } + + // Bind descriptor sets. for (uint32_t i = 0; i < cl->state.set_count; i++) { if (cl->state.sets[i].pipeline_expected_format == 0) { continue; // Nothing expected by this pipeline. @@ -4877,25 +4913,78 @@ void RenderingDevice::_end_frame() { ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work)."); } - draw_graph.end(frames[frame].draw_command_buffer, RENDER_GRAPH_REORDER, RENDER_GRAPH_FULL_BARRIERS); driver->command_buffer_end(frames[frame].setup_command_buffer); - driver->command_buffer_end(frames[frame].draw_command_buffer); + + // The command buffer must be copied into a stack variable as the driver workarounds can change the command buffer in use. + RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer; + draw_graph.end(RENDER_GRAPH_REORDER, RENDER_GRAPH_FULL_BARRIERS, command_buffer, frames[frame].command_buffer_pool); + driver->command_buffer_end(command_buffer); driver->end_segment(); } void RenderingDevice::_execute_frame(bool p_present) { + // Check whether this frame should present the swap chains and in which queue. const bool frame_can_present = p_present && !frames[frame].swap_chains_to_present.is_empty(); const bool separate_present_queue = main_queue != present_queue; - const VectorView<RDD::SemaphoreID> execute_draw_semaphore = frame_can_present && separate_present_queue ? frames[frame].draw_semaphore : VectorView<RDD::SemaphoreID>(); - const VectorView<RDD::SwapChainID> execute_draw_swap_chains = frame_can_present && !separate_present_queue ? frames[frame].swap_chains_to_present : VectorView<RDD::SwapChainID>(); + thread_local LocalVector<RDD::SwapChainID> swap_chains; + swap_chains.clear(); + + // Execute the setup command buffer. driver->command_queue_execute_and_present(main_queue, {}, frames[frame].setup_command_buffer, frames[frame].setup_semaphore, {}, {}); - driver->command_queue_execute_and_present(main_queue, frames[frame].setup_semaphore, frames[frame].draw_command_buffer, execute_draw_semaphore, frames[frame].draw_fence, execute_draw_swap_chains); + + // Execute command buffers and use semaphores to wait on the execution of the previous one. Normally there's only one command buffer, + // but driver workarounds can force situations where there'll be more. + uint32_t command_buffer_count = 1; + RDG::CommandBufferPool &buffer_pool = frames[frame].command_buffer_pool; + if (buffer_pool.buffers_used > 0) { + command_buffer_count += buffer_pool.buffers_used; + buffer_pool.buffers_used = 0; + } + + RDD::SemaphoreID wait_semaphore = frames[frame].setup_semaphore; + for (uint32_t i = 0; i < command_buffer_count; i++) { + RDD::CommandBufferID command_buffer; + RDD::SemaphoreID signal_semaphore; + RDD::FenceID signal_fence; + if (i > 0) { + command_buffer = buffer_pool.buffers[i - 1]; + signal_semaphore = buffer_pool.semaphores[i - 1]; + } else { + command_buffer = frames[frame].draw_command_buffer; + signal_semaphore = frames[frame].draw_semaphore; + } + + bool signal_semaphore_valid; + if (i == (command_buffer_count - 1)) { + // This is the last command buffer, it should signal the fence. + signal_fence = frames[frame].draw_fence; + signal_semaphore_valid = false; + + if (frame_can_present && separate_present_queue) { + // The semaphore is required if the frame can be presented and a separate present queue is used. + signal_semaphore_valid = true; + } else if (frame_can_present) { + // Just present the swap chains as part of the last command execution. + swap_chains = frames[frame].swap_chains_to_present; + } + } else { + // Semaphores always need to be signaled if it's not the last command buffer. + signal_semaphore_valid = true; + } + + driver->command_queue_execute_and_present(main_queue, wait_semaphore, command_buffer, signal_semaphore_valid ? signal_semaphore : VectorView<RDD::SemaphoreID>(), signal_fence, swap_chains); + + // Make the next command buffer wait on the semaphore signaled by this one. + wait_semaphore = signal_semaphore; + } + + // Indicate the fence has been signaled so the next time the frame's contents need to be used, the CPU needs to wait on the work to be completed. frames[frame].draw_fence_signaled = true; if (frame_can_present) { if (separate_present_queue) { // Issue the presentation separately if the presentation queue is different from the main queue. - driver->command_queue_execute_and_present(present_queue, frames[frame].draw_semaphore, {}, {}, {}, frames[frame].swap_chains_to_present); + driver->command_queue_execute_and_present(present_queue, wait_semaphore, {}, {}, {}, frames[frame].swap_chains_to_present); } frames[frame].swap_chains_to_present.clear(); @@ -5044,6 +5133,9 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ frames[i].timestamp_cpu_result_values.resize(max_timestamp_query_elements); frames[i].timestamp_result_values.resize(max_timestamp_query_elements); frames[i].timestamp_result_count = 0; + + // Assign the main queue family and command pool to the command buffer pool. + frames[i].command_buffer_pool.pool = frames[i].command_pool; } // Start from frame count, so everything else is immediately old. @@ -5055,7 +5147,7 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ driver->command_buffer_begin(frames[0].draw_command_buffer); // Create draw graph and start it initialized as well. - draw_graph.initialize(driver, frames.size(), main_queue_family, SECONDARY_COMMAND_BUFFERS_PER_FRAME); + draw_graph.initialize(driver, device, frames.size(), main_queue_family, SECONDARY_COMMAND_BUFFERS_PER_FRAME); draw_graph.begin(); for (uint32_t i = 0; i < frames.size(); i++) { @@ -5388,6 +5480,11 @@ void RenderingDevice::finalize() { driver->semaphore_free(frames[i].setup_semaphore); driver->semaphore_free(frames[i].draw_semaphore); driver->fence_free(frames[i].draw_fence); + + RDG::CommandBufferPool &buffer_pool = frames[i].command_buffer_pool; + for (uint32_t j = 0; j < buffer_pool.buffers.size(); j++) { + driver->semaphore_free(buffer_pool.semaphores[j]); + } } if (pipeline_cache_enabled) { diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 9db2fdfbf4..42773fc347 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -797,6 +797,8 @@ private: #endif public: + RenderingContextDriver *get_context_driver() const { return context; } + const RDD::Capabilities &get_device_capabilities() const { return driver->get_capabilities(); } bool has_feature(const Features p_feature) const; @@ -1261,6 +1263,9 @@ private: // Swap chains prepared for drawing during the frame that must be presented. LocalVector<RDD::SwapChainID> swap_chains_to_present; + // Extra command buffer pool used for driver workarounds. + RDG::CommandBufferPool command_buffer_pool; + struct Timestamp { String description; uint64_t value = 0; diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp index b04f2ebbaa..c7de5c67cb 100644 --- a/servers/rendering/rendering_device_graph.cpp +++ b/servers/rendering/rendering_device_graph.cpp @@ -753,71 +753,96 @@ void RenderingDeviceGraph::_wait_for_secondary_command_buffer_tasks() { } } -void RenderingDeviceGraph::_run_render_commands(RDD::CommandBufferID p_command_buffer, int32_t p_level, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, int32_t &r_current_label_index, int32_t &r_current_label_level) { +void RenderingDeviceGraph::_run_render_commands(int32_t p_level, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, RDD::CommandBufferID &r_command_buffer, CommandBufferPool &r_command_buffer_pool, int32_t &r_current_label_index, int32_t &r_current_label_level) { for (uint32_t i = 0; i < p_sorted_commands_count; i++) { const uint32_t command_index = p_sorted_commands[i].index; const uint32_t command_data_offset = command_data_offsets[command_index]; const RecordedCommand *command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]); - _run_label_command_change(p_command_buffer, command->label_index, p_level, false, true, &p_sorted_commands[i], p_sorted_commands_count - i, r_current_label_index, r_current_label_level); + _run_label_command_change(r_command_buffer, command->label_index, p_level, false, true, &p_sorted_commands[i], p_sorted_commands_count - i, r_current_label_index, r_current_label_level); switch (command->type) { case RecordedCommand::TYPE_BUFFER_CLEAR: { const RecordedBufferClearCommand *buffer_clear_command = reinterpret_cast<const RecordedBufferClearCommand *>(command); - driver->command_clear_buffer(p_command_buffer, buffer_clear_command->buffer, buffer_clear_command->offset, buffer_clear_command->size); + driver->command_clear_buffer(r_command_buffer, buffer_clear_command->buffer, buffer_clear_command->offset, buffer_clear_command->size); } break; case RecordedCommand::TYPE_BUFFER_COPY: { const RecordedBufferCopyCommand *buffer_copy_command = reinterpret_cast<const RecordedBufferCopyCommand *>(command); - driver->command_copy_buffer(p_command_buffer, buffer_copy_command->source, buffer_copy_command->destination, buffer_copy_command->region); + driver->command_copy_buffer(r_command_buffer, buffer_copy_command->source, buffer_copy_command->destination, buffer_copy_command->region); } break; case RecordedCommand::TYPE_BUFFER_GET_DATA: { const RecordedBufferGetDataCommand *buffer_get_data_command = reinterpret_cast<const RecordedBufferGetDataCommand *>(command); - driver->command_copy_buffer(p_command_buffer, buffer_get_data_command->source, buffer_get_data_command->destination, buffer_get_data_command->region); + driver->command_copy_buffer(r_command_buffer, buffer_get_data_command->source, buffer_get_data_command->destination, buffer_get_data_command->region); } break; case RecordedCommand::TYPE_BUFFER_UPDATE: { const RecordedBufferUpdateCommand *buffer_update_command = reinterpret_cast<const RecordedBufferUpdateCommand *>(command); const RecordedBufferCopy *command_buffer_copies = buffer_update_command->buffer_copies(); for (uint32_t j = 0; j < buffer_update_command->buffer_copies_count; j++) { - driver->command_copy_buffer(p_command_buffer, command_buffer_copies[j].source, buffer_update_command->destination, command_buffer_copies[j].region); + driver->command_copy_buffer(r_command_buffer, command_buffer_copies[j].source, buffer_update_command->destination, command_buffer_copies[j].region); } } break; case RecordedCommand::TYPE_COMPUTE_LIST: { + if (device.workarounds.avoid_compute_after_draw && workarounds_state.draw_list_found) { + // Avoid compute after draw workaround. Refer to the comment that enables this in the Vulkan driver for more information. + workarounds_state.draw_list_found = false; + + // Create or reuse a command buffer and finish recording the current one. + driver->command_buffer_end(r_command_buffer); + + while (r_command_buffer_pool.buffers_used >= r_command_buffer_pool.buffers.size()) { + RDD::CommandBufferID command_buffer = driver->command_buffer_create(r_command_buffer_pool.pool); + RDD::SemaphoreID command_semaphore = driver->semaphore_create(); + r_command_buffer_pool.buffers.push_back(command_buffer); + r_command_buffer_pool.semaphores.push_back(command_semaphore); + } + + // Start recording on the next usable command buffer from the pool. + uint32_t command_buffer_index = r_command_buffer_pool.buffers_used++; + r_command_buffer = r_command_buffer_pool.buffers[command_buffer_index]; + driver->command_buffer_begin(r_command_buffer); + } + const RecordedComputeListCommand *compute_list_command = reinterpret_cast<const RecordedComputeListCommand *>(command); - _run_compute_list_command(p_command_buffer, compute_list_command->instruction_data(), compute_list_command->instruction_data_size); + _run_compute_list_command(r_command_buffer, compute_list_command->instruction_data(), compute_list_command->instruction_data_size); } break; case RecordedCommand::TYPE_DRAW_LIST: { + if (device.workarounds.avoid_compute_after_draw) { + // Indicate that a draw list was encountered for the workaround. + workarounds_state.draw_list_found = true; + } + const RecordedDrawListCommand *draw_list_command = reinterpret_cast<const RecordedDrawListCommand *>(command); const VectorView clear_values(draw_list_command->clear_values(), draw_list_command->clear_values_count); - driver->command_begin_render_pass(p_command_buffer, draw_list_command->render_pass, draw_list_command->framebuffer, draw_list_command->command_buffer_type, draw_list_command->region, clear_values); - _run_draw_list_command(p_command_buffer, draw_list_command->instruction_data(), draw_list_command->instruction_data_size); - driver->command_end_render_pass(p_command_buffer); + driver->command_begin_render_pass(r_command_buffer, draw_list_command->render_pass, draw_list_command->framebuffer, draw_list_command->command_buffer_type, draw_list_command->region, clear_values); + _run_draw_list_command(r_command_buffer, draw_list_command->instruction_data(), draw_list_command->instruction_data_size); + driver->command_end_render_pass(r_command_buffer); } break; case RecordedCommand::TYPE_TEXTURE_CLEAR: { const RecordedTextureClearCommand *texture_clear_command = reinterpret_cast<const RecordedTextureClearCommand *>(command); - driver->command_clear_color_texture(p_command_buffer, texture_clear_command->texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_clear_command->color, texture_clear_command->range); + driver->command_clear_color_texture(r_command_buffer, texture_clear_command->texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_clear_command->color, texture_clear_command->range); } break; case RecordedCommand::TYPE_TEXTURE_COPY: { const RecordedTextureCopyCommand *texture_copy_command = reinterpret_cast<const RecordedTextureCopyCommand *>(command); - driver->command_copy_texture(p_command_buffer, texture_copy_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_copy_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_copy_command->region); + driver->command_copy_texture(r_command_buffer, texture_copy_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_copy_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_copy_command->region); } break; case RecordedCommand::TYPE_TEXTURE_GET_DATA: { const RecordedTextureGetDataCommand *texture_get_data_command = reinterpret_cast<const RecordedTextureGetDataCommand *>(command); const VectorView<RDD::BufferTextureCopyRegion> command_buffer_texture_copy_regions_view(texture_get_data_command->buffer_texture_copy_regions(), texture_get_data_command->buffer_texture_copy_regions_count); - driver->command_copy_texture_to_buffer(p_command_buffer, texture_get_data_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_get_data_command->to_buffer, command_buffer_texture_copy_regions_view); + driver->command_copy_texture_to_buffer(r_command_buffer, texture_get_data_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_get_data_command->to_buffer, command_buffer_texture_copy_regions_view); } break; case RecordedCommand::TYPE_TEXTURE_RESOLVE: { const RecordedTextureResolveCommand *texture_resolve_command = reinterpret_cast<const RecordedTextureResolveCommand *>(command); - driver->command_resolve_texture(p_command_buffer, texture_resolve_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_resolve_command->src_layer, texture_resolve_command->src_mipmap, texture_resolve_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_resolve_command->dst_layer, texture_resolve_command->dst_mipmap); + driver->command_resolve_texture(r_command_buffer, texture_resolve_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_resolve_command->src_layer, texture_resolve_command->src_mipmap, texture_resolve_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_resolve_command->dst_layer, texture_resolve_command->dst_mipmap); } break; case RecordedCommand::TYPE_TEXTURE_UPDATE: { const RecordedTextureUpdateCommand *texture_update_command = reinterpret_cast<const RecordedTextureUpdateCommand *>(command); const RecordedBufferToTextureCopy *command_buffer_to_texture_copies = texture_update_command->buffer_to_texture_copies(); for (uint32_t j = 0; j < texture_update_command->buffer_to_texture_copies_count; j++) { - driver->command_copy_buffer_to_texture(p_command_buffer, command_buffer_to_texture_copies[j].from_buffer, texture_update_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, command_buffer_to_texture_copies[j].region); + driver->command_copy_buffer_to_texture(r_command_buffer, command_buffer_to_texture_copies[j].from_buffer, texture_update_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, command_buffer_to_texture_copies[j].region); } } break; case RecordedCommand::TYPE_CAPTURE_TIMESTAMP: { const RecordedCaptureTimestampCommand *texture_capture_timestamp_command = reinterpret_cast<const RecordedCaptureTimestampCommand *>(command); - driver->command_timestamp_write(p_command_buffer, texture_capture_timestamp_command->pool, texture_capture_timestamp_command->index); + driver->command_timestamp_write(r_command_buffer, texture_capture_timestamp_command->pool, texture_capture_timestamp_command->index); } break; default: { DEV_ASSERT(false && "Unknown recorded command type."); @@ -1229,8 +1254,9 @@ void RenderingDeviceGraph::_print_compute_list(const uint8_t *p_instruction_data } } -void RenderingDeviceGraph::initialize(RDD *p_driver, uint32_t p_frame_count, RDD::CommandQueueFamilyID p_secondary_command_queue_family, uint32_t p_secondary_command_buffers_per_frame) { +void RenderingDeviceGraph::initialize(RDD *p_driver, RenderingContextDriver::Device p_device, uint32_t p_frame_count, RDD::CommandQueueFamilyID p_secondary_command_queue_family, uint32_t p_secondary_command_buffers_per_frame) { driver = p_driver; + device = p_device; frames.resize(p_frame_count); for (uint32_t i = 0; i < p_frame_count; i++) { @@ -1805,7 +1831,7 @@ void RenderingDeviceGraph::end_label() { command_label_index = -1; } -void RenderingDeviceGraph::end(RDD::CommandBufferID p_command_buffer, bool p_reorder_commands, bool p_full_barriers) { +void RenderingDeviceGraph::end(bool p_reorder_commands, bool p_full_barriers, RDD::CommandBufferID &r_command_buffer, CommandBufferPool &r_command_buffer_pool) { if (command_count == 0) { // No commands have been logged, do nothing. return; @@ -1919,7 +1945,12 @@ void RenderingDeviceGraph::end(RDD::CommandBufferID p_command_buffer, bool p_reo if (command_count > 0) { int32_t current_label_index = -1; int32_t current_label_level = -1; - _run_label_command_change(p_command_buffer, -1, -1, true, true, nullptr, 0, current_label_index, current_label_level); + _run_label_command_change(r_command_buffer, -1, -1, true, true, nullptr, 0, current_label_index, current_label_level); + + if (device.workarounds.avoid_compute_after_draw) { + // Reset the state of the workaround. + workarounds_state.draw_list_found = false; + } if (p_reorder_commands) { #if PRINT_RENDER_GRAPH @@ -1946,8 +1977,8 @@ void RenderingDeviceGraph::end(RDD::CommandBufferID p_command_buffer, bool p_reo RecordedCommandSort *level_command_ptr = &commands_sorted[current_level_start]; uint32_t level_command_count = i - current_level_start; _boost_priority_for_render_commands(level_command_ptr, level_command_count, boosted_priority); - _group_barriers_for_render_commands(p_command_buffer, level_command_ptr, level_command_count, p_full_barriers); - _run_render_commands(p_command_buffer, current_level, level_command_ptr, level_command_count, current_label_index, current_label_level); + _group_barriers_for_render_commands(r_command_buffer, level_command_ptr, level_command_count, p_full_barriers); + _run_render_commands(current_level, level_command_ptr, level_command_count, r_command_buffer, r_command_buffer_pool, current_label_index, current_label_level); current_level = commands_sorted[i].level; current_level_start = i; } @@ -1956,20 +1987,20 @@ void RenderingDeviceGraph::end(RDD::CommandBufferID p_command_buffer, bool p_reo RecordedCommandSort *level_command_ptr = &commands_sorted[current_level_start]; uint32_t level_command_count = command_count - current_level_start; _boost_priority_for_render_commands(level_command_ptr, level_command_count, boosted_priority); - _group_barriers_for_render_commands(p_command_buffer, level_command_ptr, level_command_count, p_full_barriers); - _run_render_commands(p_command_buffer, current_level, level_command_ptr, level_command_count, current_label_index, current_label_level); + _group_barriers_for_render_commands(r_command_buffer, level_command_ptr, level_command_count, p_full_barriers); + _run_render_commands(current_level, level_command_ptr, level_command_count, r_command_buffer, r_command_buffer_pool, current_label_index, current_label_level); #if PRINT_RENDER_GRAPH print_line("COMMANDS", command_count, "LEVELS", current_level + 1); #endif } else { for (uint32_t i = 0; i < command_count; i++) { - _group_barriers_for_render_commands(p_command_buffer, &commands_sorted[i], 1, p_full_barriers); - _run_render_commands(p_command_buffer, i, &commands_sorted[i], 1, current_label_index, current_label_level); + _group_barriers_for_render_commands(r_command_buffer, &commands_sorted[i], 1, p_full_barriers); + _run_render_commands(i, &commands_sorted[i], 1, r_command_buffer, r_command_buffer_pool, current_label_index, current_label_level); } } - _run_label_command_change(p_command_buffer, -1, -1, true, false, nullptr, 0, current_label_index, current_label_level); + _run_label_command_change(r_command_buffer, -1, -1, true, false, nullptr, 0, current_label_index, current_label_level); #if PRINT_COMMAND_RECORDING print_line(vformat("Recorded %d commands", command_count)); diff --git a/servers/rendering/rendering_device_graph.h b/servers/rendering/rendering_device_graph.h index 3bc63bb297..a96382e0cc 100644 --- a/servers/rendering/rendering_device_graph.h +++ b/servers/rendering/rendering_device_graph.h @@ -184,6 +184,20 @@ public: } }; + struct CommandBufferPool { + // Provided by RenderingDevice. + RDD::CommandPoolID pool; + + // Created internally by RenderingDeviceGraph. + LocalVector<RDD::CommandBufferID> buffers; + LocalVector<RDD::SemaphoreID> semaphores; + uint32_t buffers_used = 0; + }; + + struct WorkaroundsState { + bool draw_list_found = false; + }; + private: struct InstructionList { LocalVector<uint8_t> data; @@ -560,6 +574,7 @@ private: }; RDD *driver = nullptr; + RenderingContextDriver::Device device; int64_t tracking_frame = 0; LocalVector<uint8_t> command_data; LocalVector<uint32_t> command_data_offsets; @@ -582,6 +597,7 @@ private: bool command_synchronization_pending = false; BarrierGroup barrier_group; bool driver_honors_barriers = false; + WorkaroundsState workarounds_state; TightLocalVector<Frame> frames; uint32_t frame = 0; @@ -608,7 +624,7 @@ private: void _run_draw_list_command(RDD::CommandBufferID p_command_buffer, const uint8_t *p_instruction_data, uint32_t p_instruction_data_size); void _run_secondary_command_buffer_task(const SecondaryCommandBuffer *p_secondary); void _wait_for_secondary_command_buffer_tasks(); - void _run_render_commands(RDD::CommandBufferID p_command_buffer, int32_t p_level, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, int32_t &r_current_label_index, int32_t &r_current_label_level); + void _run_render_commands(int32_t p_level, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, RDD::CommandBufferID &r_command_buffer, CommandBufferPool &r_command_buffer_pool, int32_t &r_current_label_index, int32_t &r_current_label_level); void _run_label_command_change(RDD::CommandBufferID p_command_buffer, int32_t p_new_label_index, int32_t p_new_level, bool p_ignore_previous_value, bool p_use_label_for_empty, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, int32_t &r_current_label_index, int32_t &r_current_label_level); void _boost_priority_for_render_commands(RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, uint32_t &r_boosted_priority); void _group_barriers_for_render_commands(RDD::CommandBufferID p_command_buffer, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, bool p_full_memory_barrier); @@ -619,7 +635,7 @@ private: public: RenderingDeviceGraph(); ~RenderingDeviceGraph(); - void initialize(RDD *p_driver, uint32_t p_frame_count, RDD::CommandQueueFamilyID p_secondary_command_queue_family, uint32_t p_secondary_command_buffers_per_frame); + void initialize(RDD *p_driver, RenderingContextDriver::Device p_device, uint32_t p_frame_count, RDD::CommandQueueFamilyID p_secondary_command_queue_family, uint32_t p_secondary_command_buffers_per_frame); void finalize(); void begin(); void add_buffer_clear(RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_offset, uint32_t p_size); @@ -664,7 +680,7 @@ public: void add_synchronization(); void begin_label(const String &p_label_name, const Color &p_color); void end_label(); - void end(RDD::CommandBufferID p_command_buffer, bool p_reorder_commands, bool p_full_barriers); + void end(bool p_reorder_commands, bool p_full_barriers, RDD::CommandBufferID &r_command_buffer, CommandBufferPool &r_command_buffer_pool); static ResourceTracker *resource_tracker_create(); static void resource_tracker_free(ResourceTracker *tracker); }; diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index d0b6bc492d..164ec3cc09 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -885,9 +885,9 @@ public: FUNC6(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float, bool) FUNC5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) - FUNC4(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float) - FUNC3(canvas_item_add_rect, RID, const Rect2 &, const Color &) - FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &) + FUNC5(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) + FUNC4(canvas_item_add_rect, RID, const Rect2 &, const Color &, bool) + FUNC5(canvas_item_add_circle, RID, const Point2 &, float, const Color &, bool) FUNC6(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool) FUNC7(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, bool) FUNC8(canvas_item_add_msdf_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, int, float, float) |
