diff --git a/impeller/entity/contents/tiled_texture_contents.cc b/impeller/entity/contents/tiled_texture_contents.cc index cc1e2fd9a6cb0..fa0f8f9bee891 100644 --- a/impeller/entity/contents/tiled_texture_contents.cc +++ b/impeller/entity/contents/tiled_texture_contents.cc @@ -86,13 +86,6 @@ bool TiledTextureContents::Render(const ContentContext& renderer, if (texture_ == nullptr) { return true; } - // TODO(jonahwilliams): this is a special case for VerticesGeometry which - // implements GetPositionUVBuffer. The general geometry case does not use - // this method (see note below). - auto geometry = GetGeometry(); - if (geometry->GetVertexType() == GeometryVertexType::kUV) { - return RenderVertices(renderer, entity, pass); - } using VS = TiledTextureFillVertexShader; using FS = TiledTextureFillFragmentShader; @@ -104,21 +97,14 @@ bool TiledTextureContents::Render(const ContentContext& renderer, auto& host_buffer = pass.GetTransientsBuffer(); - auto geometry_result = - GetGeometry()->GetPositionBuffer(renderer, entity, pass); - - // TODO(bdero): The geometry should be fetched from GetPositionUVBuffer and - // contain coverage-mapped UVs, and this should use - // position_uv.vert. - // https://github.com/flutter/flutter/issues/118553 + auto bounds_origin = GetGeometry()->GetCoverage(Matrix())->origin; + auto geometry_result = GetGeometry()->GetPositionUVBuffer( + Rect(bounds_origin, Size(texture_size)), GetInverseMatrix(), renderer, + entity, pass); VS::FrameInfo frame_info; frame_info.mvp = geometry_result.transform; frame_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale(); - frame_info.effect_transform = GetInverseMatrix(); - frame_info.bounds_origin = geometry->GetCoverage(Matrix())->origin; - frame_info.texture_size = Vector2(static_cast(texture_size.width), - static_cast(texture_size.height)); FS::FragInfo frag_info; frag_info.x_tile_mode = static_cast(x_tile_mode_); @@ -169,73 +155,4 @@ bool TiledTextureContents::Render(const ContentContext& renderer, return true; } -bool TiledTextureContents::RenderVertices(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { - using VS = PositionUVPipeline::VertexShader; - using FS = PositionUVPipeline::FragmentShader; - - const auto texture_size = texture_->GetSize(); - if (texture_size.IsEmpty()) { - return true; - } - - auto& host_buffer = pass.GetTransientsBuffer(); - - auto geometry_result = GetGeometry()->GetPositionUVBuffer( - Rect::MakeSize(texture_size), GetInverseMatrix(), renderer, entity, pass); - - VS::FrameInfo frame_info; - frame_info.mvp = geometry_result.transform; - frame_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale(); - - FS::FragInfo frag_info; - frag_info.x_tile_mode = static_cast(x_tile_mode_); - frag_info.y_tile_mode = static_cast(y_tile_mode_); - frag_info.alpha = GetAlpha(); - - Command cmd; - cmd.label = "PositionUV"; - cmd.stencil_reference = entity.GetStencilDepth(); - - auto options = OptionsFromPassAndEntity(pass, entity); - if (geometry_result.prevent_overdraw) { - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; - } - options.primitive_type = geometry_result.type; - cmd.pipeline = renderer.GetPositionUVPipeline(options); - - cmd.BindVertices(geometry_result.vertex_buffer); - VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); - FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); - - if (color_filter_.has_value()) { - auto filtered_texture = CreateFilterTexture(renderer); - if (!filtered_texture.has_value()) { - return false; - } - FS::BindTextureSampler( - cmd, filtered_texture.value(), - renderer.GetContext()->GetSamplerLibrary()->GetSampler( - CreateDescriptor())); - } else { - FS::BindTextureSampler( - cmd, texture_, - renderer.GetContext()->GetSamplerLibrary()->GetSampler( - CreateDescriptor())); - } - - if (!pass.AddCommand(std::move(cmd))) { - return false; - } - - if (geometry_result.prevent_overdraw) { - auto restore = ClipRestoreContents(); - restore.SetRestoreCoverage(GetCoverage(entity)); - return restore.Render(renderer, entity, pass); - } - return true; -} - } // namespace impeller diff --git a/impeller/entity/contents/tiled_texture_contents.h b/impeller/entity/contents/tiled_texture_contents.h index 57d36ac1b157e..953d5f6c10cdc 100644 --- a/impeller/entity/contents/tiled_texture_contents.h +++ b/impeller/entity/contents/tiled_texture_contents.h @@ -53,10 +53,6 @@ class TiledTextureContents final : public ColorSourceContents { std::optional> CreateFilterTexture( const ContentContext& renderer) const; - bool RenderVertices(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const; - SamplerDescriptor CreateDescriptor() const; std::shared_ptr texture_; diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index ee2a70801b072..9afede2f048ad 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -246,6 +246,27 @@ TEST_P(EntityTest, ThreeStrokesInOnePath) { ASSERT_TRUE(OpenPlaygroundHere(entity)); } +TEST_P(EntityTest, StrokeWithTextureContents) { + auto bridge = CreateTextureForFixture("bay_bridge.jpg"); + Path path = PathBuilder{} + .MoveTo({100, 100}) + .LineTo({100, 200}) + .MoveTo({100, 300}) + .LineTo({100, 400}) + .MoveTo({100, 500}) + .LineTo({100, 600}) + .TakePath(); + + Entity entity; + entity.SetTransformation(Matrix::MakeScale(GetContentScale())); + auto contents = std::make_unique(); + contents->SetGeometry(Geometry::MakeStrokePath(path, 100.0)); + contents->SetTexture(bridge); + contents->SetTileModes(Entity::TileMode::kClamp, Entity::TileMode::kClamp); + entity.SetContents(std::move(contents)); + ASSERT_TRUE(OpenPlaygroundHere(entity)); +} + TEST_P(EntityTest, TriangleInsideASquare) { auto callback = [&](ContentContext& context, RenderPass& pass) { Point offset(100, 100); diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index 2ad20a000afb9..0c2c0d2a8ba2d 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -6,6 +6,7 @@ #include "impeller/entity/contents/content_context.h" #include "impeller/entity/entity.h" #include "impeller/entity/position_color.vert.h" +#include "impeller/entity/texture_fill.vert.h" #include "impeller/geometry/matrix.h" #include "impeller/geometry/path_builder.h" #include "impeller/renderer/device_buffer.h" @@ -52,6 +53,40 @@ std::unique_ptr Geometry::MakeRect(Rect rect) { return std::make_unique(rect); } +static GeometryResult ComputeUVGeometryForRect(Rect source_rect, + Rect texture_coverage, + Matrix effect_transform, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) { + constexpr uint16_t kRectIndicies[4] = {0, 1, 2, 3}; + auto& host_buffer = pass.GetTransientsBuffer(); + + std::vector data(8); + auto points = source_rect.GetPoints(); + for (auto i = 0u, j = 0u; i < 8; i += 2, j++) { + data[i] = points[j]; + data[i + 1] = effect_transform * ((points[j] - texture_coverage.origin) / + texture_coverage.size); + } + + return GeometryResult{ + .type = PrimitiveType::kTriangleStrip, + .vertex_buffer = + { + .vertex_buffer = host_buffer.Emplace( + data.data(), 16 * sizeof(float), alignof(float)), + .index_buffer = host_buffer.Emplace( + kRectIndicies, 4 * sizeof(uint16_t), alignof(uint16_t)), + .index_count = 4, + .index_type = IndexType::k16bit, + }, + .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(), + .prevent_overdraw = false, + }; +} + /////// Path Geometry /////// FillPathGeometry::FillPathGeometry(const Path& path) : path_(path) {} @@ -90,6 +125,51 @@ GeometryResult FillPathGeometry::GetPositionBuffer( }; } +// |Geometry| +GeometryResult FillPathGeometry::GetPositionUVBuffer( + Rect texture_coverage, + Matrix effect_transform, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) { + using VS = TextureFillVertexShader; + + VertexBufferBuilder vertex_builder; + auto tesselation_result = renderer.GetTessellator()->Tessellate( + path_.GetFillType(), + path_.CreatePolyline(entity.GetTransformation().GetMaxBasisLength()), + [&vertex_builder, &texture_coverage, &effect_transform]( + const float* vertices, size_t vertices_count, const uint16_t* indices, + size_t indices_count) { + for (auto i = 0u; i < vertices_count; i += 2) { + VS::PerVertexData data; + Point vtx = {vertices[i], vertices[i + 1]}; + data.position = vtx; + auto coverage_coords = + ((vtx - texture_coverage.origin) / texture_coverage.size) / + texture_coverage.size; + data.texture_coords = effect_transform * coverage_coords; + vertex_builder.AppendVertex(data); + } + FML_DCHECK(vertex_builder.GetVertexCount() == vertices_count / 2); + for (auto i = 0u; i < indices_count; i++) { + vertex_builder.AppendIndex(indices[i]); + } + return true; + }); + if (tesselation_result != Tessellator::Result::kSuccess) { + return {}; + } + return GeometryResult{ + .type = PrimitiveType::kTriangle, + .vertex_buffer = + vertex_builder.CreateVertexBuffer(pass.GetTransientsBuffer()), + .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(), + .prevent_overdraw = false, + }; +} + GeometryVertexType FillPathGeometry::GetVertexType() const { return GeometryVertexType::kPosition; } @@ -301,9 +381,9 @@ StrokePathGeometry::CapProc StrokePathGeometry::GetCapProc(Cap stroke_cap) { } // static -VertexBuffer StrokePathGeometry::CreateSolidStrokeVertices( +VertexBufferBuilder +StrokePathGeometry::CreateSolidStrokeVertices( const Path& path, - HostBuffer& buffer, Scalar stroke_width, Scalar scaled_miter_limit, Cap cap, @@ -423,7 +503,7 @@ VertexBuffer StrokePathGeometry::CreateSolidStrokeVertices( } } - return vtx_builder.CreateVertexBuffer(buffer); + return vtx_builder; } GeometryResult StrokePathGeometry::GetPositionBuffer( @@ -442,14 +522,58 @@ GeometryResult StrokePathGeometry::GetPositionBuffer( Scalar stroke_width = std::max(stroke_width_, min_size); auto& host_buffer = pass.GetTransientsBuffer(); - auto vertex_buffer = CreateSolidStrokeVertices( - path_, host_buffer, stroke_width, miter_limit_ * stroke_width_ * 0.5, - stroke_cap_, GetJoinProc(stroke_join_), GetCapProc(stroke_cap_), + auto vertex_builder = CreateSolidStrokeVertices( + path_, stroke_width, miter_limit_ * stroke_width_ * 0.5, stroke_cap_, + GetJoinProc(stroke_join_), GetCapProc(stroke_cap_), entity.GetTransformation().GetMaxBasisLength()); return GeometryResult{ .type = PrimitiveType::kTriangleStrip, - .vertex_buffer = vertex_buffer, + .vertex_buffer = vertex_builder.CreateVertexBuffer(host_buffer), + .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(), + .prevent_overdraw = true, + }; +} + +GeometryResult StrokePathGeometry::GetPositionUVBuffer( + Rect texture_coverage, + Matrix effect_transform, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) { + if (stroke_width_ < 0.0) { + return {}; + } + auto determinant = entity.GetTransformation().GetDeterminant(); + if (determinant == 0) { + return {}; + } + + Scalar min_size = 1.0f / sqrt(std::abs(determinant)); + Scalar stroke_width = std::max(stroke_width_, min_size); + + auto& host_buffer = pass.GetTransientsBuffer(); + auto stroke_builder = CreateSolidStrokeVertices( + path_, stroke_width, miter_limit_ * stroke_width_ * 0.5, stroke_cap_, + GetJoinProc(stroke_join_), GetCapProc(stroke_cap_), + entity.GetTransformation().GetMaxBasisLength()); + + VertexBufferBuilder vertex_builder; + stroke_builder.IterateVertices( + [&vertex_builder, &texture_coverage, + &effect_transform](SolidFillVertexShader::PerVertexData old_vtx) { + TextureFillVertexShader::PerVertexData data; + data.position = old_vtx.position; + auto coverage_coords = (old_vtx.position - texture_coverage.origin) / + texture_coverage.size; + data.texture_coords = effect_transform * coverage_coords; + vertex_builder.AppendVertex(data); + }); + + return GeometryResult{ + .type = PrimitiveType::kTriangleStrip, + .vertex_buffer = vertex_builder.CreateVertexBuffer(host_buffer), .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * entity.GetTransformation(), .prevent_overdraw = true, @@ -516,6 +640,18 @@ GeometryResult CoverGeometry::GetPositionBuffer(const ContentContext& renderer, }; } +// |Geometry| +GeometryResult CoverGeometry::GetPositionUVBuffer( + Rect texture_coverage, + Matrix effect_transform, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) { + auto rect = Rect(Size(pass.GetRenderTargetSize())); + return ComputeUVGeometryForRect(rect, texture_coverage, effect_transform, + renderer, entity, pass); +} + GeometryVertexType CoverGeometry::GetVertexType() const { return GeometryVertexType::kPosition; } @@ -552,6 +688,16 @@ GeometryResult RectGeometry::GetPositionBuffer(const ContentContext& renderer, }; } +// |Geometry| +GeometryResult RectGeometry::GetPositionUVBuffer(Rect texture_coverage, + Matrix effect_transform, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) { + return ComputeUVGeometryForRect(rect_, texture_coverage, effect_transform, + renderer, entity, pass); +} + GeometryVertexType RectGeometry::GetVertexType() const { return GeometryVertexType::kPosition; } diff --git a/impeller/entity/geometry.h b/impeller/entity/geometry.h index edc59cd5c62ac..bdf34d6830225 100644 --- a/impeller/entity/geometry.h +++ b/impeller/entity/geometry.h @@ -109,6 +109,13 @@ class FillPathGeometry : public Geometry { // |Geometry| std::optional GetCoverage(const Matrix& transform) const override; + // |Geometry| + GeometryResult GetPositionUVBuffer(Rect texture_coverage, + Matrix effect_transform, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) override; + Path path_; FML_DISALLOW_COPY_AND_ASSIGN(FillPathGeometry); @@ -154,26 +161,35 @@ class StrokePathGeometry : public Geometry { const Entity& entity, RenderPass& pass) override; + // |Geometry| + GeometryResult GetPositionUVBuffer(Rect texture_coverage, + Matrix effect_transform, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) override; + // |Geometry| GeometryVertexType GetVertexType() const override; // |Geometry| std::optional GetCoverage(const Matrix& transform) const override; + bool SkipRendering() const; + static Scalar CreateBevelAndGetDirection( VertexBufferBuilder& vtx_builder, const Point& position, const Point& start_offset, const Point& end_offset); - static VertexBuffer CreateSolidStrokeVertices(const Path& path, - HostBuffer& buffer, - Scalar stroke_width, - Scalar scaled_miter_limit, - Cap cap, - const JoinProc& join_proc, - const CapProc& cap_proc, - Scalar scale); + static VertexBufferBuilder + CreateSolidStrokeVertices(const Path& path, + Scalar stroke_width, + Scalar scaled_miter_limit, + Cap cap, + const JoinProc& join_proc, + const CapProc& cap_proc, + Scalar scale); static StrokePathGeometry::JoinProc GetJoinProc(Join stroke_join); @@ -208,6 +224,13 @@ class CoverGeometry : public Geometry { // |Geometry| std::optional GetCoverage(const Matrix& transform) const override; + // |Geometry| + GeometryResult GetPositionUVBuffer(Rect texture_coverage, + Matrix effect_transform, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) override; + FML_DISALLOW_COPY_AND_ASSIGN(CoverGeometry); }; @@ -229,6 +252,13 @@ class RectGeometry : public Geometry { // |Geometry| std::optional GetCoverage(const Matrix& transform) const override; + // |Geometry| + GeometryResult GetPositionUVBuffer(Rect texture_coverage, + Matrix effect_transform, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) override; + Rect rect_; FML_DISALLOW_COPY_AND_ASSIGN(RectGeometry); diff --git a/impeller/entity/shaders/tiled_texture_fill.vert b/impeller/entity/shaders/tiled_texture_fill.vert index 7bdce80f7fc5d..e0f2c7882936a 100644 --- a/impeller/entity/shaders/tiled_texture_fill.vert +++ b/impeller/entity/shaders/tiled_texture_fill.vert @@ -3,27 +3,21 @@ // found in the LICENSE file. #include -#include #include uniform FrameInfo { mat4 mvp; - mat4 effect_transform; - vec2 bounds_origin; - vec2 texture_size; float texture_sampler_y_coord_scale; } frame_info; in vec2 position; +in vec2 texture_coords; out vec2 v_texture_coords; void main() { gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); - v_texture_coords = IPRemapCoords( - IPVec2TransformPosition( - frame_info.effect_transform, - (position - frame_info.bounds_origin) / frame_info.texture_size), - frame_info.texture_sampler_y_coord_scale); + v_texture_coords = + IPRemapCoords(texture_coords, frame_info.texture_sampler_y_coord_scale); } diff --git a/impeller/renderer/vertex_buffer_builder.h b/impeller/renderer/vertex_buffer_builder.h index 61cfd3156ec17..4d0e29df9e0f9 100644 --- a/impeller/renderer/vertex_buffer_builder.h +++ b/impeller/renderer/vertex_buffer_builder.h @@ -91,6 +91,12 @@ class VertexBufferBuilder { return buffer; }; + void IterateVertices(const std::function& iterator) { + for (auto& vertex : vertices_) { + iterator(vertex); + } + } + private: std::vector vertices_; std::vector indices_; diff --git a/impeller/tools/malioc.json b/impeller/tools/malioc.json index 7855162a55dc8..2d7a27c04bb73 100644 --- a/impeller/tools/malioc.json +++ b/impeller/tools/malioc.json @@ -10030,7 +10030,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 22, + "uniform_registers_used": 16, "work_registers_used": 32 }, "Varying": { @@ -10041,10 +10041,10 @@ "load_store" ], "longest_path_cycles": [ - 0.125, - 0.125, 0.03125, - 0.0625, + 0.015625, + 0.03125, + 0.0, 3.0, 0.0 ], @@ -10060,10 +10060,10 @@ "load_store" ], "shortest_path_cycles": [ - 0.125, - 0.125, 0.03125, - 0.0625, + 0.015625, + 0.03125, + 0.0, 3.0, 0.0 ], @@ -10071,18 +10071,18 @@ "load_store" ], "total_cycles": [ - 0.125, - 0.125, 0.03125, - 0.0625, + 0.015625, + 0.03125, + 0.0, 3.0, 0.0 ] }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 16, - "work_registers_used": 8 + "uniform_registers_used": 10, + "work_registers_used": 7 } } }, @@ -10099,8 +10099,8 @@ "load_store" ], "longest_path_cycles": [ - 3.9600000381469727, - 4.0, + 2.9700000286102295, + 5.0, 0.0 ], "pipelines": [ @@ -10112,23 +10112,22 @@ "load_store" ], "shortest_path_cycles": [ - 3.9600000381469727, - 4.0, + 2.9700000286102295, + 5.0, 0.0 ], "total_bound_pipelines": [ - "arithmetic", "load_store" ], "total_cycles": [ - 4.0, - 4.0, + 3.0, + 5.0, 0.0 ] }, "thread_occupancy": 100, - "uniform_registers_used": 6, - "work_registers_used": 3 + "uniform_registers_used": 4, + "work_registers_used": 2 } } } @@ -12955,7 +12954,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 28, + "uniform_registers_used": 20, "work_registers_used": 32 }, "Varying": { @@ -12966,10 +12965,10 @@ "load_store" ], "longest_path_cycles": [ - 0.125, - 0.125, 0.03125, - 0.0625, + 0.015625, + 0.03125, + 0.0, 3.0, 0.0 ], @@ -12985,10 +12984,10 @@ "load_store" ], "shortest_path_cycles": [ - 0.125, - 0.125, 0.03125, - 0.0625, + 0.015625, + 0.03125, + 0.0, 3.0, 0.0 ], @@ -12996,18 +12995,18 @@ "load_store" ], "total_cycles": [ - 0.125, - 0.125, 0.03125, - 0.0625, + 0.015625, + 0.03125, + 0.0, 3.0, 0.0 ] }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 24, - "work_registers_used": 8 + "uniform_registers_used": 16, + "work_registers_used": 7 } } }