diff --git a/impeller/entity/contents/color_source_contents.h b/impeller/entity/contents/color_source_contents.h index a23fae582ab86..d5a7263e932e5 100644 --- a/impeller/entity/contents/color_source_contents.h +++ b/impeller/entity/contents/color_source_contents.h @@ -137,6 +137,9 @@ class ColorSourceContents : public Contents { GeometryResult stencil_geometry_result = GetGeometry()->GetPositionBuffer(renderer, entity, pass); + if (stencil_geometry_result.vertex_buffer.vertex_count == 0u) { + return true; + } pass.SetVertexBuffer(std::move(stencil_geometry_result.vertex_buffer)); options.primitive_type = stencil_geometry_result.type; @@ -182,6 +185,9 @@ class ColorSourceContents : public Contents { ? geometry.GetPositionUVBuffer(texture_coverage, effect_transform, renderer, entity, pass) : geometry.GetPositionBuffer(renderer, entity, pass); + if (geometry_result.vertex_buffer.vertex_count == 0u) { + return true; + } pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer)); options.primitive_type = geometry_result.type; diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 7dcebc01f8117..9b2f7bdc53595 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -2812,6 +2812,51 @@ TEST_P(EntityTest, FailOnValidationError) { ""); } +TEST_P(EntityTest, CanComputeGeometryForEmptyPathsWithoutCrashing) { + PathBuilder builder = {}; + builder.AddRect(Rect::MakeLTRB(0, 0, 0, 0)); + Path path = builder.TakePath(); + + EXPECT_TRUE(path.GetBoundingBox()->IsEmpty()); + + auto geom = Geometry::MakeFillPath(path); + + Entity entity; + RenderTarget target = + GetContentContext()->GetRenderTargetCache()->CreateOffscreen( + *GetContext(), {1, 1}, 1u); + testing::MockRenderPass render_pass(GetContext(), target); + auto position_result = + geom->GetPositionBuffer(*GetContentContext(), entity, render_pass); + + auto uv_result = + geom->GetPositionUVBuffer(Rect::MakeLTRB(0, 0, 100, 100), Matrix(), + *GetContentContext(), entity, render_pass); + + EXPECT_EQ(position_result.vertex_buffer.vertex_count, 0u); + EXPECT_EQ(uv_result.vertex_buffer.vertex_count, 0u); + + EXPECT_EQ(geom->GetResultMode(), GeometryResult::Mode::kNormal); +} + +TEST_P(EntityTest, CanRenderEmptyPathsWithoutCrashing) { + PathBuilder builder = {}; + builder.AddRect(Rect::MakeLTRB(0, 0, 0, 0)); + Path path = builder.TakePath(); + + EXPECT_TRUE(path.GetBoundingBox()->IsEmpty()); + + auto contents = std::make_shared(); + contents->SetGeometry(Geometry::MakeFillPath(path)); + contents->SetColor(Color::Red()); + + Entity entity; + entity.SetTransform(Matrix::MakeScale(GetContentScale())); + entity.SetContents(contents); + + ASSERT_TRUE(OpenPlaygroundHere(std::move(entity))); +} + } // namespace testing } // namespace impeller diff --git a/impeller/entity/geometry/fill_path_geometry.cc b/impeller/entity/geometry/fill_path_geometry.cc index e187659ce04b1..0d4f1782423ff 100644 --- a/impeller/entity/geometry/fill_path_geometry.cc +++ b/impeller/entity/geometry/fill_path_geometry.cc @@ -6,6 +6,7 @@ #include "fml/logging.h" #include "impeller/core/formats.h" +#include "impeller/core/vertex_buffer.h" #include "impeller/entity/contents/content_context.h" #include "impeller/entity/geometry/geometry.h" @@ -20,8 +21,22 @@ GeometryResult FillPathGeometry::GetPositionBuffer( const Entity& entity, RenderPass& pass) const { auto& host_buffer = renderer.GetTransientsBuffer(); - VertexBuffer vertex_buffer; + const auto& bounding_box = path_.GetBoundingBox(); + if (bounding_box.has_value() && bounding_box->IsEmpty()) { + return GeometryResult{ + .type = PrimitiveType::kTriangle, + .vertex_buffer = + VertexBuffer{ + .vertex_buffer = {}, + .vertex_count = 0, + .index_type = IndexType::k16bit, + }, + .transform = pass.GetOrthographicTransform() * entity.GetTransform(), + }; + } + + VertexBuffer vertex_buffer; if constexpr (!ContentContext::kEnableStencilThenCover) { if (!path_.IsConvex()) { auto tesselation_result = renderer.GetTessellator()->Tessellate( @@ -79,6 +94,20 @@ GeometryResult FillPathGeometry::GetPositionUVBuffer( RenderPass& pass) const { using VS = TextureFillVertexShader; + const auto& bounding_box = path_.GetBoundingBox(); + if (bounding_box.has_value() && bounding_box->IsEmpty()) { + return GeometryResult{ + .type = PrimitiveType::kTriangle, + .vertex_buffer = + VertexBuffer{ + .vertex_buffer = {}, + .vertex_count = 0, + .index_type = IndexType::k16bit, + }, + .transform = pass.GetOrthographicTransform() * entity.GetTransform(), + }; + } + auto uv_transform = texture_coverage.GetNormalizingTransform() * effect_transform; @@ -139,7 +168,9 @@ GeometryResult FillPathGeometry::GetPositionUVBuffer( } GeometryResult::Mode FillPathGeometry::GetResultMode() const { - if (!ContentContext::kEnableStencilThenCover || path_.IsConvex()) { + const auto& bounding_box = path_.GetBoundingBox(); + if (!ContentContext::kEnableStencilThenCover || path_.IsConvex() || + (bounding_box.has_value() && bounding_box->IsEmpty())) { return GeometryResult::Mode::kNormal; } diff --git a/impeller/entity/geometry/geometry_unittests.cc b/impeller/entity/geometry/geometry_unittests.cc index c56c16613bd57..990b1419659ed 100644 --- a/impeller/entity/geometry/geometry_unittests.cc +++ b/impeller/entity/geometry/geometry_unittests.cc @@ -2,11 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include #include "flutter/testing/testing.h" +#include "impeller/entity/contents/content_context.h" #include "impeller/entity/geometry/geometry.h" #include "impeller/entity/geometry/stroke_path_geometry.h" #include "impeller/geometry/geometry_asserts.h" #include "impeller/geometry/path_builder.h" +#include "impeller/renderer/testing/mocks.h" inline ::testing::AssertionResult SolidVerticesNear( std::vector a, diff --git a/impeller/tessellator/tessellator.cc b/impeller/tessellator/tessellator.cc index 8f5edc61374d5..665a6248217cb 100644 --- a/impeller/tessellator/tessellator.cc +++ b/impeller/tessellator/tessellator.cc @@ -179,6 +179,7 @@ Path::Polyline Tessellator::CreateTempPolyline(const Path& path, std::vector Tessellator::TessellateConvex(const Path& path, Scalar tolerance) { FML_DCHECK(point_buffer_); + std::vector output; point_buffer_->clear(); auto polyline =