From 961008cf1fd44bf8b3726e105a1f7cc4c1d13afd Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Sun, 7 May 2023 12:33:32 -0700 Subject: [PATCH 01/25] [Impeller] compute circles in vertex shader --- impeller/aiks/canvas.cc | 13 ++ impeller/aiks/canvas.h | 2 + impeller/display_list/dl_dispatcher.cc | 5 + impeller/display_list/skia_conversions.cc | 8 ++ impeller/display_list/skia_conversions.h | 2 + impeller/entity/BUILD.gn | 1 + impeller/entity/contents/content_context.cc | 19 +++ impeller/entity/contents/content_context.h | 23 +++- impeller/entity/geometry.cc | 118 ++++++++++++++++++ impeller/entity/geometry.h | 36 ++++++ impeller/entity/shaders/geometry/points.vert | 55 ++++++++ .../backend/metal/pipeline_library_mtl.mm | 1 + impeller/renderer/pipeline_builder.h | 46 ++++--- impeller/renderer/pipeline_descriptor.cc | 12 +- impeller/renderer/pipeline_descriptor.h | 5 + 15 files changed, 326 insertions(+), 20 deletions(-) create mode 100644 impeller/entity/shaders/geometry/points.vert diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 662ea009cd6ce..4e4562853bcec 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -373,6 +373,19 @@ void Canvas::RestoreClip() { GetCurrentPass().AddEntity(entity); } +void Canvas::DrawPoints(std::vector points, + Scalar radius, + const Paint& paint) { + Entity entity; + entity.SetTransformation(GetCurrentTransformation()); + entity.SetStencilDepth(GetStencilDepth()); + entity.SetBlendMode(paint.blend_mode); + entity.SetContents(paint.WithFilters(paint.CreateContentsForGeometry( + Geometry::MakePointField(std::move(points), radius)))); + + GetCurrentPass().AddEntity(entity); +} + void Canvas::DrawPicture(Picture picture) { if (!picture.pass) { return; diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index 54be12491b09d..c177ba90cd00e 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -100,6 +100,8 @@ class Canvas { void DrawCircle(Point center, Scalar radius, const Paint& paint); + void DrawPoints(std::vector, Scalar radius, const Paint& paint); + void DrawImage(const std::shared_ptr& image, Point offset, const Paint& paint, diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index 157efbaee69a7..d9134817ecb76 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -918,6 +918,11 @@ void DlDispatcher::drawPoints(PointMode mode, if (paint.stroke_cap == Cap::kButt) { paint.stroke_cap = Cap::kSquare; } + if (paint.stroke_cap == Cap::kRound) { + canvas_.DrawPoints(skia_conversions::ToPoints(points, count), + paint.stroke_width, paint); + break; + } for (uint32_t i = 0; i < count; i++) { Point p0 = skia_conversions::ToPoint(points[i]); auto path = PathBuilder{}.AddLine(p0, p0).TakePath(); diff --git a/impeller/display_list/skia_conversions.cc b/impeller/display_list/skia_conversions.cc index 7b54fef8a552d..572583e0c3830 100644 --- a/impeller/display_list/skia_conversions.cc +++ b/impeller/display_list/skia_conversions.cc @@ -26,6 +26,14 @@ std::vector ToRects(const SkRect tex[], int count) { return result; } +std::vector ToPoints(const SkPoint points[], int count) { + std::vector result(count); + for (auto i = 0; i < count; i++) { + result[i] = ToPoint(points[i]); + } + return result; +} + PathBuilder::RoundingRadii ToRoundingRadii(const SkRRect& rrect) { using Corner = SkRRect::Corner; PathBuilder::RoundingRadii radii; diff --git a/impeller/display_list/skia_conversions.h b/impeller/display_list/skia_conversions.h index 933875bee7101..5f1524674240d 100644 --- a/impeller/display_list/skia_conversions.h +++ b/impeller/display_list/skia_conversions.h @@ -26,6 +26,8 @@ std::optional ToRect(const SkRect* rect); std::vector ToRects(const SkRect tex[], int count); +std::vector ToPoints(const SkPoint points[], int count); + Point ToPoint(const SkPoint& point); Color ToColor(const SkColor& color); diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 91ffdae65d58b..c4135b9df1901 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -97,6 +97,7 @@ impeller_shaders("modern_entity_shaders") { "shaders/linear_gradient_ssbo_fill.frag", "shaders/radial_gradient_ssbo_fill.frag", "shaders/sweep_gradient_ssbo_fill.frag", + "shaders/geometry/points.vert", ] } diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index a8f1e8e54151b..c05774e422bca 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -144,6 +144,7 @@ void ContentContextOptions::ApplyToPipelineDescriptor( desc.SetPrimitiveType(primitive_type); desc.SetPolygonMode(wireframe ? PolygonMode::kLine : PolygonMode::kFill); + desc.SetEnableRasterization(enable_rasterization); } template @@ -161,6 +162,22 @@ static std::unique_ptr CreateDefaultPipeline( return std::make_unique(context, desc); } +template +static std::unique_ptr CreateDefaultNonRenderingPipeline( + const Context& context) { + auto desc = PipelineT::Builder::MakeDefaultPipelineDescriptor(context); + if (!desc.has_value()) { + return nullptr; + } + // Apply default ContentContextOptions to the descriptor. + const auto default_color_fmt = + context.GetCapabilities()->GetDefaultColorFormat(); + ContentContextOptions{.color_attachment_pixel_format = default_color_fmt, + .enable_rasterization = false} + .ApplyToPipelineDescriptor(*desc); + return std::make_unique(context, desc); +} + ContentContext::ContentContext(std::shared_ptr context) : context_(std::move(context)), tessellator_(std::make_shared()), @@ -294,6 +311,8 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); porter_duff_blend_pipelines_[{}] = CreateDefaultPipeline(*context_); + point_field_geometry_pipelines_[{}] = + CreateDefaultNonRenderingPipeline(*context_); if (solid_fill_pipelines_[{}]->GetDescriptor().has_value()) { auto clip_pipeline_descriptor = diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 65941ceda19f4..d0dc2dcc84014 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -40,6 +40,7 @@ #include "impeller/entity/linear_to_srgb_filter.vert.h" #include "impeller/entity/morphology_filter.frag.h" #include "impeller/entity/morphology_filter.vert.h" +#include "impeller/entity/points.vert.h" #include "impeller/entity/porter_duff_blend.frag.h" #include "impeller/entity/radial_gradient_fill.frag.h" #include "impeller/entity/rrect_blur.frag.h" @@ -275,6 +276,9 @@ using FramebufferBlendScreenPipeline = using FramebufferBlendSoftLightPipeline = RenderPipelineT; +/// Geometry Pipelines +using PointFieldGeometryPipeline = + RenderPipelineT; /// Pipeline state configuration. /// @@ -295,13 +299,14 @@ struct ContentContextOptions { std::optional color_attachment_pixel_format; bool has_stencil_attachment = true; bool wireframe = false; + bool enable_rasterization = true; struct Hash { constexpr std::size_t operator()(const ContentContextOptions& o) const { - return fml::HashCombine(o.sample_count, o.blend_mode, o.stencil_compare, - o.stencil_operation, o.primitive_type, - o.color_attachment_pixel_format, - o.has_stencil_attachment, o.wireframe); + return fml::HashCombine( + o.sample_count, o.blend_mode, o.stencil_compare, o.stencil_operation, + o.primitive_type, o.color_attachment_pixel_format, + o.has_stencil_attachment, o.wireframe, o.enable_rasterization); } }; @@ -316,7 +321,8 @@ struct ContentContextOptions { lhs.color_attachment_pixel_format == rhs.color_attachment_pixel_format && lhs.has_stencil_attachment == rhs.has_stencil_attachment && - lhs.wireframe == rhs.wireframe; + lhs.wireframe == rhs.wireframe && + lhs.enable_rasterization == rhs.enable_rasterization; } }; @@ -661,6 +667,11 @@ class ContentContext { return GetPipeline(framebuffer_blend_softlight_pipelines_, opts); } + std::shared_ptr> GetPointFieldGeometryPipeline( + ContentContextOptions opts) const { + return GetPipeline(point_field_geometry_pipelines_, opts); + } + std::shared_ptr GetContext() const; std::shared_ptr GetGlyphAtlasContext() const; @@ -783,6 +794,8 @@ class ContentContext { mutable Variants framebuffer_blend_softlight_pipelines_; + mutable Variants point_field_geometry_pipelines_; + template std::shared_ptr> GetPipeline( Variants& container, diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index 612d9cb3a1af2..d07006ad6e618 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -4,6 +4,7 @@ #include "impeller/entity/geometry.h" +#include #include "impeller/core/device_buffer.h" #include "impeller/entity/contents/content_context.h" #include "impeller/entity/entity.h" @@ -38,6 +39,13 @@ std::unique_ptr Geometry::MakeRRect(Rect rect, Scalar corner_radius) { return std::make_unique(rect, corner_radius); } +// static +std::unique_ptr Geometry::MakePointField(std::vector points, + Scalar radius) { + return std::make_unique(std::move(points), radius); +} + +// static std::unique_ptr Geometry::MakeStrokePath(const Path& path, Scalar stroke_width, Scalar miter_limit, @@ -883,4 +891,114 @@ std::optional RRectGeometry::GetCoverage(const Matrix& transform) const { return rect_.TransformBounds(transform); } +/////// PointFieldGeometry Geometry /////// + +PointFieldGeometry::PointFieldGeometry(std::vector points, Scalar radius) + : points_(std::move(points)), radius_(radius) {} + +PointFieldGeometry::~PointFieldGeometry() = default; + +GeometryResult PointFieldGeometry::GetPositionBuffer( + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) { + auto divisions_per_circle = ComputeResultSize( + entity.GetTransformation().GetMaxBasisLength() * radius_, points_.size()); + auto total = divisions_per_circle * points_.size() * 3; + auto& host_buffer = pass.GetTransientsBuffer(); + + using VS = PointFieldGeometryPipeline::VertexShader; + VertexBufferBuilder vertex_builder; + for (auto i = 0u; i < points_.size(); i++) { + vertex_builder.AppendVertex( + {.center = points_[i], .offset = static_cast(i)}); + } + + DeviceBufferDescriptor buffer_desc; + buffer_desc.size = total * sizeof(Point); + buffer_desc.storage_mode = StorageMode::kDevicePrivate; + + auto buffer = + renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc); + + // Create Dummy index buffer. + auto index_count = divisions_per_circle * points_.size() * 3; + std::vector dummy_index(index_count); + for (auto i = 0u; i < index_count; i++) { + dummy_index[i] = i; + } + auto index_buffer = host_buffer.Emplace( + dummy_index.data(), index_count * sizeof(uint32_t), alignof(uint32_t)); + + Command cmd; + cmd.label = "Points Geometry"; + + auto options = OptionsFromPass(pass); + options.blend_mode = BlendMode::kSource; + options.stencil_compare = CompareFunction::kAlways; + options.stencil_operation = StencilOperation::kKeep; + options.enable_rasterization = false; + cmd.pipeline = renderer.GetPointFieldGeometryPipeline(options); + + VS::FrameInfo frame_info; + frame_info.radius = radius_; + frame_info.radian_step = k2Pi / divisions_per_circle; + frame_info.points_per_circle = divisions_per_circle * 3; + frame_info.divisions_per_circle = divisions_per_circle; + frame_info.total_length = total; + + VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); + VS::BindGeometryData( + cmd, {.buffer = buffer, .range = Range{0, total * sizeof(Point)}}); + + cmd.BindVertices(vertex_builder.CreateVertexBuffer(host_buffer)); + + if (!pass.AddCommand(std::move(cmd))) { + return {}; + } + + return { + .type = PrimitiveType::kTriangle, + .vertex_buffer = {.vertex_buffer = {.buffer = buffer, + .range = + Range{0, total * sizeof(Point)}}, + + .index_buffer = index_buffer, + .index_count = index_count, + .index_type = IndexType::k32bit}, + .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(), + .prevent_overdraw = false, + }; +} + +GeometryResult PointFieldGeometry::GetPositionUVBuffer( + Rect texture_coverage, + Matrix effect_transform, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) { + return {}; +} + +/// @brief Compute the exact storage size needed to store the resulting buffer. +/// @return +size_t PointFieldGeometry::ComputeResultSize(Scalar scaled_radius, + size_t point_count) { + // note: this formula is completely arbitrary, we should find a reasonable + // curve based on experimental data. + return 8; +} + +// |Geometry| +GeometryVertexType PointFieldGeometry::GetVertexType() const { + return GeometryVertexType::kPosition; +} + +// |Geometry| +std::optional PointFieldGeometry::GetCoverage( + const Matrix& transform) const { + return Rect::MakeMaximum(); +} + } // namespace impeller diff --git a/impeller/entity/geometry.h b/impeller/entity/geometry.h index bcf9190766a32..7c4a3b786f377 100644 --- a/impeller/entity/geometry.h +++ b/impeller/entity/geometry.h @@ -54,6 +54,9 @@ class Geometry { static std::unique_ptr MakeRect(Rect rect); + static std::unique_ptr MakePointField(std::vector points, + Scalar radius); + virtual GeometryResult GetPositionBuffer(const ContentContext& renderer, const Entity& entity, RenderPass& pass) = 0; @@ -290,4 +293,37 @@ class RRectGeometry : public Geometry { FML_DISALLOW_COPY_AND_ASSIGN(RRectGeometry); }; +class PointFieldGeometry : public Geometry { + public: + explicit PointFieldGeometry(std::vector points, Scalar radius); + + ~PointFieldGeometry(); + + private: + // |Geometry| + GeometryResult GetPositionBuffer(const ContentContext& renderer, + 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; + + static size_t ComputeResultSize(Scalar scaled_radius, size_t point_count); + + std::vector points_; + Scalar radius_; + + FML_DISALLOW_COPY_AND_ASSIGN(PointFieldGeometry); +}; + } // namespace impeller diff --git a/impeller/entity/shaders/geometry/points.vert b/impeller/entity/shaders/geometry/points.vert new file mode 100644 index 0000000000000..330a1a8ff3e10 --- /dev/null +++ b/impeller/entity/shaders/geometry/points.vert @@ -0,0 +1,55 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +// TODO(jonahwilliams): with some adjustments to start and end angles, +// this could draw squars and closed arcs too. + +uniform FrameInfo { + float radius; + float16_t radian_step; + int points_per_circle; + int divisions_per_circle; + int total_length; +} +frame_info; + +layout(std430) writeonly buffer GeometryData { + vec2 geometry[]; +} +geometry_data; + +in vec2 center; +in int offset; + +void main() { + // The buffer offset we start writing to is the number of data per circle * + // number of previous circles. + int bufer_offset = offset * frame_info.points_per_circle; + + float16_t elapsed_angle = 0.0hf; + geometry_data.geometry[bufer_offset++] = center; + + vec2 pt1 = center + vec2(1, 0) * frame_info.radius; + geometry_data.geometry[bufer_offset++] = pt1; + + elapsed_angle += frame_info.radian_step; + vec2 pt2 = + center + vec2(cos(elapsed_angle), sin(elapsed_angle)) * frame_info.radius; + geometry_data.geometry[bufer_offset++] = pt2; + + for (int i = 1; i < frame_info.divisions_per_circle; i++) { + geometry_data.geometry[bufer_offset++] = center; + + pt1 = pt2; + elapsed_angle += frame_info.radian_step; + geometry_data.geometry[bufer_offset++] = pt1; + + pt2 = center + + vec2(cos(elapsed_angle), sin(elapsed_angle)) * frame_info.radius; + geometry_data.geometry[bufer_offset++] = pt2; + } +} diff --git a/impeller/renderer/backend/metal/pipeline_library_mtl.mm b/impeller/renderer/backend/metal/pipeline_library_mtl.mm index c65e31f1e7a43..e7b74e55499e2 100644 --- a/impeller/renderer/backend/metal/pipeline_library_mtl.mm +++ b/impeller/renderer/backend/metal/pipeline_library_mtl.mm @@ -27,6 +27,7 @@ auto descriptor = [[MTLRenderPipelineDescriptor alloc] init]; descriptor.label = @(desc.GetLabel().c_str()); descriptor.rasterSampleCount = static_cast(desc.GetSampleCount()); + descriptor.rasterizationEnabled = desc.GetRasterizationEnabled(); for (const auto& entry : desc.GetStageEntrypoints()) { if (entry.first == ShaderStage::kVertex) { diff --git a/impeller/renderer/pipeline_builder.h b/impeller/renderer/pipeline_builder.h index b27c4bc753b55..213375603d3ff 100644 --- a/impeller/renderer/pipeline_builder.h +++ b/impeller/renderer/pipeline_builder.h @@ -16,6 +16,15 @@ namespace impeller { +class NonRenderingFragment { + public: + static constexpr std::string_view kLabel = "NonRendering"; + static constexpr std::string_view kEntrypointName = "non_rendering_main"; + static constexpr ShaderStage kShaderStage = ShaderStage::kFragment; + static constexpr std::string_view kGeneratorName = ""; + static constexpr std::array kDescriptorSetLayouts{}; +}; + //------------------------------------------------------------------------------ /// @brief An optional (but highly recommended) utility for creating /// pipelines from reflected shader information. @@ -52,35 +61,44 @@ struct PipelineBuilder { PipelineDescriptor desc; if (InitializePipelineDescriptorDefaults(context, desc)) { return {std::move(desc)}; - } else { - return std::nullopt; } + return std::nullopt; } [[nodiscard]] static bool InitializePipelineDescriptorDefaults( const Context& context, PipelineDescriptor& desc) { // Setup debug instrumentation. - desc.SetLabel(SPrintF("%s Pipeline", FragmentShader::kLabel.data())); + if (!std::is_same::value) { + desc.SetLabel(SPrintF("%s Pipeline", FragmentShader::kLabel.data())); + } // Resolve pipeline entrypoints. { auto vertex_function = context.GetShaderLibrary()->GetFunction( VertexShader::kEntrypointName, ShaderStage::kVertex); - auto fragment_function = context.GetShaderLibrary()->GetFunction( - FragmentShader::kEntrypointName, ShaderStage::kFragment); - - if (!vertex_function || !fragment_function) { - VALIDATION_LOG << "Could not resolve pipeline entrypoint(s) '" - << VertexShader::kEntrypointName << "' and '" - << FragmentShader::kEntrypointName - << "' for pipeline named '" << VertexShader::kLabel - << "'."; - return false; + + std::shared_ptr fragment_function; + if (!std::is_same::value) { + fragment_function = context.GetShaderLibrary()->GetFunction( + FragmentShader::kEntrypointName, ShaderStage::kFragment); + } + + if (!std::is_same::value) { + if (!vertex_function || !fragment_function) { + VALIDATION_LOG << "Could not resolve pipeline entrypoint(s) '" + << VertexShader::kEntrypointName << "' and '" + << FragmentShader::kEntrypointName + << "' for pipeline named '" << VertexShader::kLabel + << "'."; + return false; + } } desc.AddStageEntrypoint(std::move(vertex_function)); - desc.AddStageEntrypoint(std::move(fragment_function)); + if (fragment_function != nullptr) { + desc.AddStageEntrypoint(std::move(fragment_function)); + } } // Setup the vertex descriptor from reflected information. diff --git a/impeller/renderer/pipeline_descriptor.cc b/impeller/renderer/pipeline_descriptor.cc index eef517b30c847..a0541a60c4168 100644 --- a/impeller/renderer/pipeline_descriptor.cc +++ b/impeller/renderer/pipeline_descriptor.cc @@ -42,6 +42,7 @@ std::size_t PipelineDescriptor::GetHash() const { fml::HashCombineSeed(seed, cull_mode_); fml::HashCombineSeed(seed, primitive_type_); fml::HashCombineSeed(seed, polygon_mode_); + fml::HashCombineSeed(seed, enable_rasterization_); return seed; } @@ -61,7 +62,8 @@ bool PipelineDescriptor::IsEqual(const PipelineDescriptor& other) const { winding_order_ == other.winding_order_ && cull_mode_ == other.cull_mode_ && primitive_type_ == other.primitive_type_ && - polygon_mode_ == other.polygon_mode_; + polygon_mode_ == other.polygon_mode_ && + enable_rasterization_ == other.enable_rasterization_; } PipelineDescriptor& PipelineDescriptor::SetLabel(std::string label) { @@ -235,6 +237,14 @@ PixelFormat PipelineDescriptor::GetDepthPixelFormat() const { return depth_pixel_format_; } +void PipelineDescriptor::SetEnableRasterization(bool value) { + enable_rasterization_ = value; +} + +bool PipelineDescriptor::GetRasterizationEnabled() const { + return enable_rasterization_; +} + std::optional PipelineDescriptor::GetBackStencilAttachmentDescriptor() const { return back_stencil_attachment_descriptor_; diff --git a/impeller/renderer/pipeline_descriptor.h b/impeller/renderer/pipeline_descriptor.h index 3d0eddf880e28..0769c7231a585 100644 --- a/impeller/renderer/pipeline_descriptor.h +++ b/impeller/renderer/pipeline_descriptor.h @@ -131,6 +131,10 @@ class PipelineDescriptor final : public Comparable { PolygonMode GetPolygonMode() const; + void SetEnableRasterization(bool value); + + bool GetRasterizationEnabled() const; + private: std::string label_; SampleCount sample_count_ = SampleCount::kCount1; @@ -149,6 +153,7 @@ class PipelineDescriptor final : public Comparable { back_stencil_attachment_descriptor_; PrimitiveType primitive_type_ = PrimitiveType::kTriangle; PolygonMode polygon_mode_ = PolygonMode::kFill; + bool enable_rasterization_ = true; }; } // namespace impeller From 56638b07705cfd5dc792fa899517bd116f146bf5 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Sun, 7 May 2023 17:47:15 -0700 Subject: [PATCH 02/25] ++ --- impeller/entity/geometry.cc | 39 ++++++++++++++------ impeller/entity/shaders/geometry/points.vert | 3 +- impeller/renderer/vertex_buffer_builder.h | 4 +- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index d07006ad6e618..039665a44bfbc 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -908,12 +908,24 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( auto& host_buffer = pass.GetTransientsBuffer(); using VS = PointFieldGeometryPipeline::VertexShader; - VertexBufferBuilder vertex_builder; - for (auto i = 0u; i < points_.size(); i++) { - vertex_builder.AppendVertex( - {.center = points_[i], .offset = static_cast(i)}); + + // Create Dummy index buffer. + auto index_count = divisions_per_circle * points_.size() * 3; + std::vector dummy_index(index_count); + for (auto i = 0u; i < index_count; i++) { + dummy_index[i] = i; } + auto vtx_buffer = VertexBuffer{ + .vertex_buffer = host_buffer.Emplace( + points_.data(), points_.size() * sizeof(Point), alignof(Point)), + .index_buffer = host_buffer.Emplace(dummy_index.data(), + points_.size() * sizeof(uint32_t), + alignof(uint32_t)), + .index_count = points_.size(), + .index_type = IndexType::k32bit, + }; + DeviceBufferDescriptor buffer_desc; buffer_desc.size = total * sizeof(Point); buffer_desc.storage_mode = StorageMode::kDevicePrivate; @@ -921,12 +933,6 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( auto buffer = renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc); - // Create Dummy index buffer. - auto index_count = divisions_per_circle * points_.size() * 3; - std::vector dummy_index(index_count); - for (auto i = 0u; i < index_count; i++) { - dummy_index[i] = i; - } auto index_buffer = host_buffer.Emplace( dummy_index.data(), index_count * sizeof(uint32_t), alignof(uint32_t)); @@ -951,7 +957,7 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( VS::BindGeometryData( cmd, {.buffer = buffer, .range = Range{0, total * sizeof(Point)}}); - cmd.BindVertices(vertex_builder.CreateVertexBuffer(host_buffer)); + cmd.BindVertices(vtx_buffer); if (!pass.AddCommand(std::move(cmd))) { return {}; @@ -987,7 +993,16 @@ size_t PointFieldGeometry::ComputeResultSize(Scalar scaled_radius, size_t point_count) { // note: this formula is completely arbitrary, we should find a reasonable // curve based on experimental data. - return 8; + if (scaled_radius < 4.0) { + return 8; + } + if (scaled_radius < 16) { + return 16; + } + if (scaled_radius < 32) { + return 32; + } + return 64; } // |Geometry| diff --git a/impeller/entity/shaders/geometry/points.vert b/impeller/entity/shaders/geometry/points.vert index 330a1a8ff3e10..c55be1cedd03a 100644 --- a/impeller/entity/shaders/geometry/points.vert +++ b/impeller/entity/shaders/geometry/points.vert @@ -23,12 +23,11 @@ layout(std430) writeonly buffer GeometryData { geometry_data; in vec2 center; -in int offset; void main() { // The buffer offset we start writing to is the number of data per circle * // number of previous circles. - int bufer_offset = offset * frame_info.points_per_circle; + int bufer_offset = gl_VertexIndex * frame_info.points_per_circle; float16_t elapsed_angle = 0.0hf; geometry_data.geometry[bufer_offset++] = center; diff --git a/impeller/renderer/vertex_buffer_builder.h b/impeller/renderer/vertex_buffer_builder.h index 96c114202f4cf..c49387830f7ad 100644 --- a/impeller/renderer/vertex_buffer_builder.h +++ b/impeller/renderer/vertex_buffer_builder.h @@ -128,9 +128,9 @@ class VertexBufferBuilder { // So dumb! We don't actually need an index buffer right now. But we will // once de-duplication is done. So assume this is always done. - std::vector index_buffer; + std::vector index_buffer(vertices_.size()); for (size_t i = 0; i < vertices_.size(); i++) { - index_buffer.push_back(i); + index_buffer[i] = i; } return index_buffer; } From be1332ad0db7f3eaf11594762124f24b6c9c19d0 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 8 May 2023 09:40:39 -0700 Subject: [PATCH 03/25] capabilities and license --- ci/licenses_golden/licenses_flutter | 2 ++ impeller/entity/contents/content_context.cc | 8 ++++++-- impeller/entity/contents/content_context.h | 2 ++ impeller/entity/geometry.cc | 6 +++--- impeller/entity/shaders/geometry/points.vert | 1 - impeller/renderer/backend/metal/context_mtl.mm | 1 + impeller/renderer/capabilities.cc | 15 +++++++++++++++ impeller/renderer/capabilities.h | 5 +++++ impeller/renderer/capabilities_unittests.cc | 1 + impeller/renderer/pipeline_builder.h | 2 +- 10 files changed, 36 insertions(+), 7 deletions(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index ffcb36dbe7f3f..cfd577956b31b 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1295,6 +1295,7 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_alp ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_alpha_nodecal.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_decal.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/shaders/geometry/points.vert + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.frag + ../../../flutter/LICENSE @@ -3889,6 +3890,7 @@ FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_alpha FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_alpha_nodecal.frag FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_decal.frag FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag +FILE: ../../../flutter/impeller/entity/shaders/geometry/points.vert FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.frag diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index c05774e422bca..ac9610ad1b9a1 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -311,8 +311,12 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); porter_duff_blend_pipelines_[{}] = CreateDefaultPipeline(*context_); - point_field_geometry_pipelines_[{}] = - CreateDefaultNonRenderingPipeline(*context_); + + if (context_->GetCapabilities()->SupportsDisabledRasterization()) { + point_field_geometry_pipelines_[{}] = + CreateDefaultNonRenderingPipeline( + *context_); + } if (solid_fill_pipelines_[{}]->GetDescriptor().has_value()) { auto clip_pipeline_descriptor = diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index d0dc2dcc84014..4396e271ecd9d 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -276,6 +276,7 @@ using FramebufferBlendScreenPipeline = using FramebufferBlendSoftLightPipeline = RenderPipelineT; + /// Geometry Pipelines using PointFieldGeometryPipeline = RenderPipelineT; @@ -669,6 +670,7 @@ class ContentContext { std::shared_ptr> GetPointFieldGeometryPipeline( ContentContextOptions opts) const { + FML_DCHECK(GetDeviceCapabilities().SupportsDisabledRasterization()); return GetPipeline(point_field_geometry_pipelines_, opts); } diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index 039665a44bfbc..3f475c0f722ff 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -902,6 +902,8 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( const ContentContext& renderer, const Entity& entity, RenderPass& pass) { + FML_DCHECK(renderer.GetDeviceCapabilities().SupportsDisabledRasterization()); + auto divisions_per_circle = ComputeResultSize( entity.GetTransformation().GetMaxBasisLength() * radius_, points_.size()); auto total = divisions_per_circle * points_.size() * 3; @@ -951,7 +953,6 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( frame_info.radian_step = k2Pi / divisions_per_circle; frame_info.points_per_circle = divisions_per_circle * 3; frame_info.divisions_per_circle = divisions_per_circle; - frame_info.total_length = total; VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); VS::BindGeometryData( @@ -968,7 +969,6 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( .vertex_buffer = {.vertex_buffer = {.buffer = buffer, .range = Range{0, total * sizeof(Point)}}, - .index_buffer = index_buffer, .index_count = index_count, .index_type = IndexType::k32bit}, @@ -984,7 +984,7 @@ GeometryResult PointFieldGeometry::GetPositionUVBuffer( const ContentContext& renderer, const Entity& entity, RenderPass& pass) { - return {}; + FML_UNREACHABLE(); } /// @brief Compute the exact storage size needed to store the resulting buffer. diff --git a/impeller/entity/shaders/geometry/points.vert b/impeller/entity/shaders/geometry/points.vert index c55be1cedd03a..65cb764c62786 100644 --- a/impeller/entity/shaders/geometry/points.vert +++ b/impeller/entity/shaders/geometry/points.vert @@ -13,7 +13,6 @@ uniform FrameInfo { float16_t radian_step; int points_per_circle; int divisions_per_circle; - int total_length; } frame_info; diff --git a/impeller/renderer/backend/metal/context_mtl.mm b/impeller/renderer/backend/metal/context_mtl.mm index c83f5b7075c47..12862b76f81e3 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -62,6 +62,7 @@ static bool DeviceSupportsComputeSubgroups(id device) { .SetSupportsComputeSubgroups(DeviceSupportsComputeSubgroups(device)) .SetSupportsReadFromResolve(true) .SetSupportsReadFromOnscreenTexture(true) + .SetSupportsDisabledRasterization(true) .Build(); } diff --git a/impeller/renderer/capabilities.cc b/impeller/renderer/capabilities.cc index d0531f5f265b2..bb41c2644261a 100644 --- a/impeller/renderer/capabilities.cc +++ b/impeller/renderer/capabilities.cc @@ -66,6 +66,11 @@ class StandardCapabilities final : public Capabilities { return supports_decal_tile_mode_; } + // |Capabilities| + bool SupportsDisabledRasterization() const override { + return supports_disabled_rasterization_; + } + // |Capabilities| PixelFormat GetDefaultColorFormat() const override { return default_color_format_; @@ -88,6 +93,7 @@ class StandardCapabilities final : public Capabilities { bool supports_read_from_onscreen_texture, bool supports_read_from_resolve, bool supports_decal_tile_mode, + bool supports_disabled_rasterization, PixelFormat default_color_format, PixelFormat default_stencil_format) : has_threading_restrictions_(has_threading_restrictions), @@ -102,6 +108,7 @@ class StandardCapabilities final : public Capabilities { supports_read_from_onscreen_texture), supports_read_from_resolve_(supports_read_from_resolve), supports_decal_tile_mode_(supports_decal_tile_mode), + supports_disabled_rasterization_(supports_disabled_rasterization), default_color_format_(default_color_format), default_stencil_format_(default_stencil_format) {} @@ -118,6 +125,7 @@ class StandardCapabilities final : public Capabilities { bool supports_read_from_onscreen_texture_ = false; bool supports_read_from_resolve_ = false; bool supports_decal_tile_mode_ = false; + bool supports_disabled_rasterization_ = false; PixelFormat default_color_format_ = PixelFormat::kUnknown; PixelFormat default_stencil_format_ = PixelFormat::kUnknown; @@ -202,6 +210,12 @@ CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsDecalTileMode(bool value) { return *this; } +CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsDisabledRasterization( + bool value) { + supports_disabled_rasterization_ = value; + return *this; +} + std::unique_ptr CapabilitiesBuilder::Build() { return std::unique_ptr(new StandardCapabilities( // has_threading_restrictions_, // @@ -215,6 +229,7 @@ std::unique_ptr CapabilitiesBuilder::Build() { supports_read_from_onscreen_texture_, // supports_read_from_resolve_, // supports_decal_tile_mode_, // + supports_disabled_rasterization_, // *default_color_format_, // *default_stencil_format_ // )); diff --git a/impeller/renderer/capabilities.h b/impeller/renderer/capabilities.h index 6fb1118dd7c95..a0ce72baa0f62 100644 --- a/impeller/renderer/capabilities.h +++ b/impeller/renderer/capabilities.h @@ -37,6 +37,8 @@ class Capabilities { virtual bool SupportsDecalTileMode() const = 0; + virtual bool SupportsDisabledRasterization() const = 0; + virtual PixelFormat GetDefaultColorFormat() const = 0; virtual PixelFormat GetDefaultStencilFormat() const = 0; @@ -79,6 +81,8 @@ class CapabilitiesBuilder { CapabilitiesBuilder& SetSupportsDecalTileMode(bool value); + CapabilitiesBuilder& SetSupportsDisabledRasterization(bool value); + std::unique_ptr Build(); private: @@ -93,6 +97,7 @@ class CapabilitiesBuilder { bool supports_read_from_onscreen_texture_ = false; bool supports_read_from_resolve_ = false; bool supports_decal_tile_mode_ = false; + bool supports_disabled_rasterization_ = false; std::optional default_color_format_ = std::nullopt; std::optional default_stencil_format_ = std::nullopt; diff --git a/impeller/renderer/capabilities_unittests.cc b/impeller/renderer/capabilities_unittests.cc index 1dc9d17e3c678..1b95a01481e1f 100644 --- a/impeller/renderer/capabilities_unittests.cc +++ b/impeller/renderer/capabilities_unittests.cc @@ -29,6 +29,7 @@ CAPABILITY_TEST(SupportsComputeSubgroups, false); CAPABILITY_TEST(SupportsReadFromOnscreenTexture, false); CAPABILITY_TEST(SupportsReadFromResolve, false); CAPABILITY_TEST(SupportsDecalTileMode, false); +CAPABILITY_TEST(SupportsDisabledRasterization, false); } // namespace testing } // namespace impeller diff --git a/impeller/renderer/pipeline_builder.h b/impeller/renderer/pipeline_builder.h index 213375603d3ff..caf8115690904 100644 --- a/impeller/renderer/pipeline_builder.h +++ b/impeller/renderer/pipeline_builder.h @@ -21,7 +21,7 @@ class NonRenderingFragment { static constexpr std::string_view kLabel = "NonRendering"; static constexpr std::string_view kEntrypointName = "non_rendering_main"; static constexpr ShaderStage kShaderStage = ShaderStage::kFragment; - static constexpr std::string_view kGeneratorName = ""; + static constexpr std::string_view kGeneratorName = "NonRendering"; static constexpr std::array kDescriptorSetLayouts{}; }; From 7a83b0dd9f81df803140bf7e17292ab921c99135 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 8 May 2023 10:34:43 -0700 Subject: [PATCH 04/25] add support for square caps --- impeller/aiks/canvas.cc | 5 +++-- impeller/aiks/canvas.h | 8 ++++++- impeller/display_list/dl_dispatcher.cc | 22 ++++++------------- impeller/entity/geometry.cc | 23 +++++++++++++------- impeller/entity/geometry.h | 8 ++++--- impeller/entity/shaders/geometry/points.vert | 6 +++-- 6 files changed, 41 insertions(+), 31 deletions(-) diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 4e4562853bcec..9e07a1c6f0c0a 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -375,13 +375,14 @@ void Canvas::RestoreClip() { void Canvas::DrawPoints(std::vector points, Scalar radius, - const Paint& paint) { + const Paint& paint, + PointStyle point_style) { Entity entity; entity.SetTransformation(GetCurrentTransformation()); entity.SetStencilDepth(GetStencilDepth()); entity.SetBlendMode(paint.blend_mode); entity.SetContents(paint.WithFilters(paint.CreateContentsForGeometry( - Geometry::MakePointField(std::move(points), radius)))); + Geometry::MakePointField(std::move(points), radius, /*round=*/point_style == PointStyle::kRound)))); GetCurrentPass().AddEntity(entity); } diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index c177ba90cd00e..8143726c68a80 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -37,6 +37,12 @@ struct CanvasStackEntry { bool contains_clips = false; }; +enum PointStyle { + kRound, + + kSquare, +}; + class Canvas { public: struct DebugOptions { @@ -100,7 +106,7 @@ class Canvas { void DrawCircle(Point center, Scalar radius, const Paint& paint); - void DrawPoints(std::vector, Scalar radius, const Paint& paint); + void DrawPoints(std::vector, Scalar radius, const Paint& paint, PointStyle point_style); void DrawImage(const std::shared_ptr& image, Point offset, diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index d9134817ecb76..56865b047f919 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -914,21 +914,13 @@ void DlDispatcher::drawPoints(PointMode mode, Paint paint = paint_; paint.style = Paint::Style::kStroke; switch (mode) { - case flutter::DlCanvas::PointMode::kPoints: - if (paint.stroke_cap == Cap::kButt) { - paint.stroke_cap = Cap::kSquare; - } - if (paint.stroke_cap == Cap::kRound) { - canvas_.DrawPoints(skia_conversions::ToPoints(points, count), - paint.stroke_width, paint); - break; - } - for (uint32_t i = 0; i < count; i++) { - Point p0 = skia_conversions::ToPoint(points[i]); - auto path = PathBuilder{}.AddLine(p0, p0).TakePath(); - canvas_.DrawPath(path, paint); - } - break; + case flutter::DlCanvas::PointMode::kPoints: { + // Cap::kButt is also treated as a square. + auto point_style = paint.stroke_cap == Cap::kRound ? PointStyle::kRound + : PointStyle::kSquare; + canvas_.DrawPoints(skia_conversions::ToPoints(points, count), + paint.stroke_width, paint, point_style); + } break; case flutter::DlCanvas::PointMode::kLines: for (uint32_t i = 1; i < count; i += 2) { Point p0 = skia_conversions::ToPoint(points[i - 1]); diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index 3f475c0f722ff..dd0b8a24f5c69 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -41,8 +41,9 @@ std::unique_ptr Geometry::MakeRRect(Rect rect, Scalar corner_radius) { // static std::unique_ptr Geometry::MakePointField(std::vector points, - Scalar radius) { - return std::make_unique(std::move(points), radius); + Scalar radius, + bool round) { + return std::make_unique(std::move(points), radius, round); } // static @@ -893,8 +894,10 @@ std::optional RRectGeometry::GetCoverage(const Matrix& transform) const { /////// PointFieldGeometry Geometry /////// -PointFieldGeometry::PointFieldGeometry(std::vector points, Scalar radius) - : points_(std::move(points)), radius_(radius) {} +PointFieldGeometry::PointFieldGeometry(std::vector points, + Scalar radius, + bool round) + : points_(std::move(points)), radius_(radius), round_(round) {} PointFieldGeometry::~PointFieldGeometry() = default; @@ -904,8 +907,8 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( RenderPass& pass) { FML_DCHECK(renderer.GetDeviceCapabilities().SupportsDisabledRasterization()); - auto divisions_per_circle = ComputeResultSize( - entity.GetTransformation().GetMaxBasisLength() * radius_, points_.size()); + auto divisions_per_circle = ComputeCircleDivisions( + entity.GetTransformation().GetMaxBasisLength() * radius_, round_); auto total = divisions_per_circle * points_.size() * 3; auto& host_buffer = pass.GetTransientsBuffer(); @@ -950,6 +953,7 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( VS::FrameInfo frame_info; frame_info.radius = radius_; + frame_info.radian_start = round_ ? 0 : 0.785398; frame_info.radian_step = k2Pi / divisions_per_circle; frame_info.points_per_circle = divisions_per_circle * 3; frame_info.divisions_per_circle = divisions_per_circle; @@ -989,8 +993,11 @@ GeometryResult PointFieldGeometry::GetPositionUVBuffer( /// @brief Compute the exact storage size needed to store the resulting buffer. /// @return -size_t PointFieldGeometry::ComputeResultSize(Scalar scaled_radius, - size_t point_count) { +size_t PointFieldGeometry::ComputeCircleDivisions(Scalar scaled_radius, + bool round) { + if (!round) { + return 4; + } // note: this formula is completely arbitrary, we should find a reasonable // curve based on experimental data. if (scaled_radius < 4.0) { diff --git a/impeller/entity/geometry.h b/impeller/entity/geometry.h index 7c4a3b786f377..bc296c438a3e9 100644 --- a/impeller/entity/geometry.h +++ b/impeller/entity/geometry.h @@ -55,7 +55,8 @@ class Geometry { static std::unique_ptr MakeRect(Rect rect); static std::unique_ptr MakePointField(std::vector points, - Scalar radius); + Scalar radius, + bool round); virtual GeometryResult GetPositionBuffer(const ContentContext& renderer, const Entity& entity, @@ -295,7 +296,7 @@ class RRectGeometry : public Geometry { class PointFieldGeometry : public Geometry { public: - explicit PointFieldGeometry(std::vector points, Scalar radius); + PointFieldGeometry(std::vector points, Scalar radius, bool round); ~PointFieldGeometry(); @@ -318,10 +319,11 @@ class PointFieldGeometry : public Geometry { // |Geometry| std::optional GetCoverage(const Matrix& transform) const override; - static size_t ComputeResultSize(Scalar scaled_radius, size_t point_count); + static size_t ComputeCircleDivisions(Scalar scaled_radius, bool round); std::vector points_; Scalar radius_; + bool round_; FML_DISALLOW_COPY_AND_ASSIGN(PointFieldGeometry); }; diff --git a/impeller/entity/shaders/geometry/points.vert b/impeller/entity/shaders/geometry/points.vert index 65cb764c62786..ed5f1c2e50011 100644 --- a/impeller/entity/shaders/geometry/points.vert +++ b/impeller/entity/shaders/geometry/points.vert @@ -10,6 +10,7 @@ uniform FrameInfo { float radius; + float16_t radian_start; float16_t radian_step; int points_per_circle; int divisions_per_circle; @@ -28,10 +29,11 @@ void main() { // number of previous circles. int bufer_offset = gl_VertexIndex * frame_info.points_per_circle; - float16_t elapsed_angle = 0.0hf; + float16_t elapsed_angle = frame_info.radian_start; geometry_data.geometry[bufer_offset++] = center; - vec2 pt1 = center + vec2(1, 0) * frame_info.radius; + vec2 pt1 = + center + vec2(cos(elapsed_angle), sin(elapsed_angle)) * frame_info.radius; geometry_data.geometry[bufer_offset++] = pt1; elapsed_angle += frame_info.radian_step; From d36a4527c44957f3f6f493843dbeb1cbb04e6ce4 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 8 May 2023 10:46:46 -0700 Subject: [PATCH 05/25] ++ --- impeller/aiks/canvas.cc | 3 ++- impeller/aiks/canvas.h | 5 ++++- impeller/entity/shaders/geometry/points.vert | 7 ++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 9e07a1c6f0c0a..6a4726a39caf7 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -382,7 +382,8 @@ void Canvas::DrawPoints(std::vector points, entity.SetStencilDepth(GetStencilDepth()); entity.SetBlendMode(paint.blend_mode); entity.SetContents(paint.WithFilters(paint.CreateContentsForGeometry( - Geometry::MakePointField(std::move(points), radius, /*round=*/point_style == PointStyle::kRound)))); + Geometry::MakePointField(std::move(points), radius, + /*round=*/point_style == PointStyle::kRound)))); GetCurrentPass().AddEntity(entity); } diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index 8143726c68a80..e5ebc8cb317f4 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -106,7 +106,10 @@ class Canvas { void DrawCircle(Point center, Scalar radius, const Paint& paint); - void DrawPoints(std::vector, Scalar radius, const Paint& paint, PointStyle point_style); + void DrawPoints(std::vector, + Scalar radius, + const Paint& paint, + PointStyle point_style); void DrawImage(const std::shared_ptr& image, Point offset, diff --git a/impeller/entity/shaders/geometry/points.vert b/impeller/entity/shaders/geometry/points.vert index ed5f1c2e50011..3828392ec03a7 100644 --- a/impeller/entity/shaders/geometry/points.vert +++ b/impeller/entity/shaders/geometry/points.vert @@ -5,11 +5,8 @@ #include #include -// TODO(jonahwilliams): with some adjustments to start and end angles, -// this could draw squars and closed arcs too. - uniform FrameInfo { - float radius; + float16_t radius; float16_t radian_start; float16_t radian_step; int points_per_circle; @@ -22,7 +19,7 @@ layout(std430) writeonly buffer GeometryData { } geometry_data; -in vec2 center; +in f16vec2 center; void main() { // The buffer offset we start writing to is the number of data per circle * From 69ea8a985d8b79136ce1c9ad54bfd8d2141fdf1e Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 8 May 2023 11:56:26 -0700 Subject: [PATCH 06/25] ++ --- impeller/renderer/backend/vulkan/capabilities_vk.cc | 4 ++++ impeller/renderer/backend/vulkan/capabilities_vk.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.cc b/impeller/renderer/backend/vulkan/capabilities_vk.cc index ff4410f15935a..1416ed07e0436 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -352,6 +352,10 @@ bool CapabilitiesVK::SupportsDecalTileMode() const { return true; } +bool CapabilitiesVK::SupportsDisabledRasterization() const { + return true; +} + // |Capabilities| PixelFormat CapabilitiesVK::GetDefaultColorFormat() const { return color_format_; diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.h b/impeller/renderer/backend/vulkan/capabilities_vk.h index 006ed6f0e0889..90d01b445bd9f 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.h +++ b/impeller/renderer/backend/vulkan/capabilities_vk.h @@ -79,6 +79,9 @@ class CapabilitiesVK final : public Capabilities, // |Capabilities| bool SupportsDecalTileMode() const override; + // |Capabilities| + bool SupportsDisabledRasterization() const override; + // |Capabilities| PixelFormat GetDefaultColorFormat() const override; From 6a830a7711999f57065d12e375334eeade3dc706 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 8 May 2023 15:07:53 -0700 Subject: [PATCH 07/25] ++ --- impeller/tools/malioc.json | 61 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/impeller/tools/malioc.json b/impeller/tools/malioc.json index e9e21d268c9d4..f3fe83a8b7f54 100644 --- a/impeller/tools/malioc.json +++ b/impeller/tools/malioc.json @@ -12327,6 +12327,67 @@ } } }, + "flutter/impeller/entity/points.vert.vkspv": { + "Mali-G78": { + "core": "Mali-G78", + "filename": "flutter/impeller/entity/points.vert.vkspv", + "has_uniform_computation": true, + "type": "Vertex", + "variants": { + "Position": { + "fp16_arithmetic": 30, + "has_stack_spilling": false, + "performance": { + "longest_path_bound_pipelines": [ + null + ], + "longest_path_cycles": [ + null, + null, + null, + null, + null, + null + ], + "pipelines": [ + "arith_total", + "arith_fma", + "arith_cvt", + "arith_sfu", + "load_store", + "texture" + ], + "shortest_path_bound_pipelines": [ + "load_store" + ], + "shortest_path_cycles": [ + 0.203125, + 0.03125, + 0.203125, + 0.0625, + 3.0, + 0.0 + ], + "total_bound_pipelines": [ + "load_store" + ], + "total_cycles": [ + 0.375, + 0.203125, + 0.375, + 0.1875, + 5.0, + 0.0 + ] + }, + "stack_spill_bytes": 0, + "thread_occupancy": 100, + "uniform_registers_used": 12, + "work_registers_used": 17 + } + } + } + }, "flutter/impeller/entity/porter_duff_blend.frag.vkspv": { "Mali-G78": { "core": "Mali-G78", From 5cec1a4bd919c92725ef18a81858d1cd5d10ceca Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 8 May 2023 15:09:13 -0700 Subject: [PATCH 08/25] switch to enum class and add docs --- impeller/aiks/canvas.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index e5ebc8cb317f4..5833317c0072b 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -37,9 +37,11 @@ struct CanvasStackEntry { bool contains_clips = false; }; -enum PointStyle { +enum class PointStyle { + /// @brief Points are drawn as squares. kRound, + /// @brief Points are drawn as circles. kSquare, }; From de05b5c232367f45b90b74b6aaf2a6b1ae1126d8 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 8 May 2023 19:35:33 -0700 Subject: [PATCH 09/25] fix offsets --- impeller/entity/shaders/geometry/points.vert | 2 +- impeller/renderer/pipeline_builder.h | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/impeller/entity/shaders/geometry/points.vert b/impeller/entity/shaders/geometry/points.vert index 3828392ec03a7..5e3a748b6e353 100644 --- a/impeller/entity/shaders/geometry/points.vert +++ b/impeller/entity/shaders/geometry/points.vert @@ -19,7 +19,7 @@ layout(std430) writeonly buffer GeometryData { } geometry_data; -in f16vec2 center; +in vec2 center; void main() { // The buffer offset we start writing to is the number of data per circle * diff --git a/impeller/renderer/pipeline_builder.h b/impeller/renderer/pipeline_builder.h index caf8115690904..a567f43c23093 100644 --- a/impeller/renderer/pipeline_builder.h +++ b/impeller/renderer/pipeline_builder.h @@ -18,10 +18,10 @@ namespace impeller { class NonRenderingFragment { public: - static constexpr std::string_view kLabel = "NonRendering"; - static constexpr std::string_view kEntrypointName = "non_rendering_main"; + static constexpr std::string_view kLabel = ""; + static constexpr std::string_view kEntrypointName = ""; static constexpr ShaderStage kShaderStage = ShaderStage::kFragment; - static constexpr std::string_view kGeneratorName = "NonRendering"; + static constexpr std::string_view kGeneratorName = ""; static constexpr std::array kDescriptorSetLayouts{}; }; @@ -71,6 +71,8 @@ struct PipelineBuilder { // Setup debug instrumentation. if (!std::is_same::value) { desc.SetLabel(SPrintF("%s Pipeline", FragmentShader::kLabel.data())); + } else { + desc.SetLabel(SPrintF("%s Pipeline", VertexShader::kLabel.data())); } // Resolve pipeline entrypoints. @@ -93,6 +95,14 @@ struct PipelineBuilder { << "'."; return false; } + } else { + if (!vertex_function) { + VALIDATION_LOG << "Could not resolve pipeline entrypoint(s) '" + << FragmentShader::kEntrypointName + << "' for pipeline named '" << VertexShader::kLabel + << "'."; + return false; + } } desc.AddStageEntrypoint(std::move(vertex_function)); From f0a82973898c8d7e19fd34f5d472d933c8096c33 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 10 May 2023 09:48:43 -0700 Subject: [PATCH 10/25] use different render pass --- impeller/entity/geometry.cc | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index c4693e970c25a..30afa0f11ece8 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -4,7 +4,6 @@ #include "impeller/entity/geometry.h" -#include #include "impeller/core/device_buffer.h" #include "impeller/entity/contents/content_context.h" #include "impeller/entity/entity.h" @@ -12,6 +11,7 @@ #include "impeller/entity/texture_fill.vert.h" #include "impeller/geometry/matrix.h" #include "impeller/geometry/path_builder.h" +#include "impeller/renderer/command_buffer.h" #include "impeller/renderer/render_pass.h" #include "impeller/tessellator/tessellator.h" @@ -969,7 +969,7 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( // Create Dummy index buffer. auto index_count = divisions_per_circle * points_.size() * 3; - std::vector dummy_index(index_count); + std::vector dummy_index(index_count); for (auto i = 0u; i < index_count; i++) { dummy_index[i] = i; } @@ -978,10 +978,10 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( .vertex_buffer = host_buffer.Emplace( points_.data(), points_.size() * sizeof(Point), alignof(Point)), .index_buffer = host_buffer.Emplace(dummy_index.data(), - points_.size() * sizeof(uint32_t), - alignof(uint32_t)), + points_.size() * sizeof(uint16_t), + alignof(uint16_t)), .index_count = points_.size(), - .index_type = IndexType::k32bit, + .index_type = IndexType::k16bit, }; DeviceBufferDescriptor buffer_desc; @@ -992,7 +992,7 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc); auto index_buffer = host_buffer.Emplace( - dummy_index.data(), index_count * sizeof(uint32_t), alignof(uint32_t)); + dummy_index.data(), index_count * sizeof(uint16_t), alignof(uint16_t)); Command cmd; cmd.label = "Points Geometry"; @@ -1006,7 +1006,7 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( VS::FrameInfo frame_info; frame_info.radius = radius_; - frame_info.radian_start = round_ ? 0 : 0.785398; + frame_info.radian_start = round_ ? 0.0f : 0.785398f; frame_info.radian_step = k2Pi / divisions_per_circle; frame_info.points_per_circle = divisions_per_circle * 3; frame_info.divisions_per_circle = divisions_per_circle; @@ -1017,8 +1017,18 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( cmd.BindVertices(vtx_buffer); - if (!pass.AddCommand(std::move(cmd))) { - return {}; + // Ensure correct synchronization by submitting vertex computation into + // a different render pass. + { + auto render_target = pass.GetRenderTarget(); + auto cmd_buffer = renderer.GetContext()->CreateCommandBuffer(); + auto vertex_render_pass = cmd_buffer->CreateRenderPass(render_target); + + if (!vertex_render_pass->AddCommand(std::move(cmd)) || + !vertex_render_pass->EncodeCommands() || + !vertex_render_pass->SubmitCommands()) { + return {}; + } } return { @@ -1028,7 +1038,7 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( Range{0, total * sizeof(Point)}}, .index_buffer = index_buffer, .index_count = index_count, - .index_type = IndexType::k32bit}, + .index_type = IndexType::k16bit}, .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * entity.GetTransformation(), .prevent_overdraw = false, @@ -1044,7 +1054,8 @@ GeometryResult PointFieldGeometry::GetPositionUVBuffer( FML_UNREACHABLE(); } -/// @brief Compute the exact storage size needed to store the resulting buffer. +/// @brief Compute the exact storage size needed to store the resulting +/// buffer. /// @return size_t PointFieldGeometry::ComputeCircleDivisions(Scalar scaled_radius, bool round) { From faba06fb3eda11bbad079269dab8f757cac49e30 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 10 May 2023 10:26:39 -0700 Subject: [PATCH 11/25] fix merge --- impeller/entity/geometry.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index b727e59be1a6c..5511fd079f7fa 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -893,7 +893,7 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( if (!vertex_render_pass->AddCommand(std::move(cmd)) || !vertex_render_pass->EncodeCommands() || - !vertex_render_pass->SubmitCommands()) { + !cmd_buffer->SubmitCommands()) { return {}; } } From a8e410674fff5cd68d18bfccc790338971299438 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 10 May 2023 12:09:18 -0700 Subject: [PATCH 12/25] add CPU fallback --- impeller/entity/geometry.cc | 52 ++++++++++++++++++++++++++++++++++++- impeller/entity/geometry.h | 4 +++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index 5511fd079f7fa..e7abbcb19dac4 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -825,7 +825,9 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( const ContentContext& renderer, const Entity& entity, RenderPass& pass) { - FML_DCHECK(renderer.GetDeviceCapabilities().SupportsDisabledRasterization()); + if (!renderer.GetDeviceCapabilities().SupportsDisabledRasterization()) { + return GetPositionBufferCPU(renderer, entity, pass); + } auto divisions_per_circle = ComputeCircleDivisions( entity.GetTransformation().GetMaxBasisLength() * radius_, round_); @@ -912,6 +914,54 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( }; } +GeometryResult PointFieldGeometry::GetPositionBufferCPU( + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) { + auto divisions_per_circle = ComputeCircleDivisions( + entity.GetTransformation().GetMaxBasisLength() * radius_, round_); + auto total = divisions_per_circle * points_.size() * 3; + auto& host_buffer = pass.GetTransientsBuffer(); + auto radian_start = round_ ? 0.0f : 0.785398f; + auto radian_step = k2Pi / divisions_per_circle; + + VertexBufferBuilder vtx_builder; + vtx_builder.Reserve(total); + vtx_builder.ReserveIndices(total); + for (auto i = 0u; i < points_.size(); i++) { + auto elapsed_angle = radian_start; + auto center = points_[i]; + vtx_builder.AppendVertex({center}); + + auto pt1 = center + Point(cos(elapsed_angle), sin(elapsed_angle)) * radius_; + vtx_builder.AppendVertex({pt1}); + + elapsed_angle += radian_step; + auto pt2 = center + Point(cos(elapsed_angle), sin(elapsed_angle)) * radius_; + vtx_builder.AppendVertex({pt2}); + + for (auto j = 0u; j < divisions_per_circle; j++) { + vtx_builder.AppendVertex({center}); + + pt1 = pt2; + elapsed_angle += radian_step; + vtx_builder.AppendVertex({pt1}); + + pt2 = center + + Point(cos(elapsed_angle), sin(elapsed_angle)) * radius_; + vtx_builder.AppendVertex({pt2}); + } + } + + return { + .type = PrimitiveType::kTriangle, + .vertex_buffer = vtx_builder.CreateVertexBuffer(host_buffer), + .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(), + .prevent_overdraw = false, + }; +} + GeometryResult PointFieldGeometry::GetPositionUVBuffer( Rect texture_coverage, Matrix effect_transform, diff --git a/impeller/entity/geometry.h b/impeller/entity/geometry.h index ae42174454c33..6937d173e7bc2 100644 --- a/impeller/entity/geometry.h +++ b/impeller/entity/geometry.h @@ -291,6 +291,10 @@ class PointFieldGeometry : public Geometry { static size_t ComputeCircleDivisions(Scalar scaled_radius, bool round); + GeometryResult GetPositionBufferCPU(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass); + std::vector points_; Scalar radius_; bool round_; From 8b8f4f813bffe184e1acb740fd3c3a5cf26ebc2f Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 10 May 2023 12:10:28 -0700 Subject: [PATCH 13/25] ++ --- impeller/entity/geometry.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index e7abbcb19dac4..c76e920392017 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -947,8 +947,7 @@ GeometryResult PointFieldGeometry::GetPositionBufferCPU( elapsed_angle += radian_step; vtx_builder.AppendVertex({pt1}); - pt2 = center + - Point(cos(elapsed_angle), sin(elapsed_angle)) * radius_; + pt2 = center + Point(cos(elapsed_angle), sin(elapsed_angle)) * radius_; vtx_builder.AppendVertex({pt2}); } } From b23b6163243cd51ff6e71233188d03126657c6c4 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 10 May 2023 12:25:16 -0700 Subject: [PATCH 14/25] fix off by one --- impeller/entity/geometry.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index c76e920392017..ffdd79fe8fb2b 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -927,7 +927,7 @@ GeometryResult PointFieldGeometry::GetPositionBufferCPU( VertexBufferBuilder vtx_builder; vtx_builder.Reserve(total); - vtx_builder.ReserveIndices(total); + for (auto i = 0u; i < points_.size(); i++) { auto elapsed_angle = radian_start; auto center = points_[i]; @@ -940,7 +940,7 @@ GeometryResult PointFieldGeometry::GetPositionBufferCPU( auto pt2 = center + Point(cos(elapsed_angle), sin(elapsed_angle)) * radius_; vtx_builder.AppendVertex({pt2}); - for (auto j = 0u; j < divisions_per_circle; j++) { + for (auto j = 1u; j < divisions_per_circle; j++) { vtx_builder.AppendVertex({center}); pt1 = pt2; From 0591bf1cf2b18327f07cad884578ac11ac7a1d62 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 11 May 2023 14:52:03 -0700 Subject: [PATCH 15/25] non working index buffer removal --- impeller/core/formats.h | 2 + impeller/core/vertex_buffer.h | 2 +- impeller/display_list/dl_dispatcher.cc | 2 +- impeller/entity/geometry.cc | 56 +++++++++---------- .../renderer/backend/metal/render_pass_mtl.mm | 13 ++++- impeller/renderer/render_pass.cc | 22 ++++---- 6 files changed, 53 insertions(+), 44 deletions(-) diff --git a/impeller/core/formats.h b/impeller/core/formats.h index 7fc4a6f221eb6..820983bbab653 100644 --- a/impeller/core/formats.h +++ b/impeller/core/formats.h @@ -308,6 +308,8 @@ enum class IndexType { kUnknown, k16bit, k32bit, + // Do not use the index buffer. + kNone, }; enum class PrimitiveType { diff --git a/impeller/core/vertex_buffer.h b/impeller/core/vertex_buffer.h index 4e8850f752803..accb0f73e0f6c 100644 --- a/impeller/core/vertex_buffer.h +++ b/impeller/core/vertex_buffer.h @@ -16,7 +16,7 @@ struct VertexBuffer { IndexType index_type = IndexType::kUnknown; constexpr operator bool() const { - return static_cast(vertex_buffer) && static_cast(index_buffer); + return static_cast(vertex_buffer); // && static_cast(index_buffer); } }; diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index 72373d797fb07..fdb8ffd2bab24 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -935,7 +935,7 @@ void DlDispatcher::drawPoints(PointMode mode, auto point_style = paint.stroke_cap == Cap::kRound ? PointStyle::kRound : PointStyle::kSquare; canvas_.DrawPoints(skia_conversions::ToPoints(points, count), - paint.stroke_width, paint, point_style); + paint.stroke_width / 2.0, paint, point_style); } break; case flutter::DlCanvas::PointMode::kLines: for (uint32_t i = 1; i < count; i += 2) { diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index ffdd79fe8fb2b..30c0668a626f9 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "impeller/entity/geometry.h" +#include #include "impeller/core/device_buffer.h" #include "impeller/entity/contents/content_context.h" @@ -825,6 +826,10 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( const ContentContext& renderer, const Entity& entity, RenderPass& pass) { + if (radius_ <= 0) { + return {}; + } + if (!renderer.GetDeviceCapabilities().SupportsDisabledRasterization()) { return GetPositionBufferCPU(renderer, entity, pass); } @@ -836,21 +841,11 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( using VS = PointFieldGeometryPipeline::VertexShader; - // Create Dummy index buffer. - auto index_count = divisions_per_circle * points_.size() * 3; - std::vector dummy_index(index_count); - for (auto i = 0u; i < index_count; i++) { - dummy_index[i] = i; - } - auto vtx_buffer = VertexBuffer{ .vertex_buffer = host_buffer.Emplace( points_.data(), points_.size() * sizeof(Point), alignof(Point)), - .index_buffer = host_buffer.Emplace(dummy_index.data(), - points_.size() * sizeof(uint16_t), - alignof(uint16_t)), .index_count = points_.size(), - .index_type = IndexType::k16bit, + .index_type = IndexType::kNone, }; DeviceBufferDescriptor buffer_desc; @@ -860,9 +855,6 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( auto buffer = renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc); - auto index_buffer = host_buffer.Emplace( - dummy_index.data(), index_count * sizeof(uint16_t), alignof(uint16_t)); - Command cmd; cmd.label = "Points Geometry"; @@ -905,9 +897,8 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( .vertex_buffer = {.vertex_buffer = {.buffer = buffer, .range = Range{0, total * sizeof(Point)}}, - .index_buffer = index_buffer, - .index_count = index_count, - .index_type = IndexType::k16bit}, + .index_count = divisions_per_circle * points_.size() * 3, + .index_type = IndexType::kNone}, .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * entity.GetTransformation(), .prevent_overdraw = false, @@ -925,7 +916,8 @@ GeometryResult PointFieldGeometry::GetPositionBufferCPU( auto radian_start = round_ ? 0.0f : 0.785398f; auto radian_step = k2Pi / divisions_per_circle; - VertexBufferBuilder vtx_builder; + VertexBufferBuilder + vtx_builder; vtx_builder.Reserve(total); for (auto i = 0u; i < points_.size(); i++) { @@ -940,7 +932,7 @@ GeometryResult PointFieldGeometry::GetPositionBufferCPU( auto pt2 = center + Point(cos(elapsed_angle), sin(elapsed_angle)) * radius_; vtx_builder.AppendVertex({pt2}); - for (auto j = 1u; j < divisions_per_circle; j++) { + for (auto j = 0u; j < divisions_per_circle - 1; j++) { vtx_builder.AppendVertex({center}); pt1 = pt2; @@ -978,18 +970,22 @@ size_t PointFieldGeometry::ComputeCircleDivisions(Scalar scaled_radius, if (!round) { return 4; } - // note: this formula is completely arbitrary, we should find a reasonable - // curve based on experimental data. - if (scaled_radius < 4.0) { + + // Note: these values are approximated based on the values returned from + // the decomposition of 4 cubics performed by Path::CreatePolyline. + if (scaled_radius < 1.0) { + return 4; + } + if (scaled_radius < 2.0) { return 8; } - if (scaled_radius < 16) { - return 16; + if (scaled_radius < 12.0) { + return 24; } - if (scaled_radius < 32) { - return 32; + if (scaled_radius < 22.0) { + return 34; } - return 64; + return std::min(scaled_radius, 140.0f); } // |Geometry| @@ -1000,7 +996,11 @@ GeometryVertexType PointFieldGeometry::GetVertexType() const { // |Geometry| std::optional PointFieldGeometry::GetCoverage( const Matrix& transform) const { - return Rect::MakeMaximum(); + auto pt_bounds = Rect::MakePointBounds(points_.begin(), points_.end()); + if (pt_bounds.has_value()) { + return pt_bounds->TransformBounds(transform); + } + return std::nullopt; } } // namespace impeller diff --git a/impeller/renderer/backend/metal/render_pass_mtl.mm b/impeller/renderer/backend/metal/render_pass_mtl.mm index 4c912e9772935..3cd982ed6b8ca 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.mm +++ b/impeller/renderer/backend/metal/render_pass_mtl.mm @@ -3,7 +3,7 @@ // found in the LICENSE file. #include "impeller/renderer/backend/metal/render_pass_mtl.h" - +#include #include "flutter/fml/closure.h" #include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h" @@ -486,6 +486,15 @@ static bool Bind(PassBindingsCache& pass, ShaderStage::kFragment)) { return false; } + const PrimitiveType primitive_type = pipeline_desc.GetPrimitiveType(); + + if (command.index_type == IndexType::kNone) { + [encoder drawPrimitives:ToMTLPrimitiveType(primitive_type) + vertexStart:command.base_vertex + vertexCount:command.index_count]; + return true; + } + if (command.index_type == IndexType::kUnknown) { return false; } @@ -503,8 +512,6 @@ static bool Bind(PassBindingsCache& pass, return false; } - const PrimitiveType primitive_type = pipeline_desc.GetPrimitiveType(); - FML_DCHECK(command.index_count * (command.index_type == IndexType::k16bit ? 2 : 4) == command.index_buffer.range.length); diff --git a/impeller/renderer/render_pass.cc b/impeller/renderer/render_pass.cc index d4e0bde02908a..f46855f1daad9 100644 --- a/impeller/renderer/render_pass.cc +++ b/impeller/renderer/render_pass.cc @@ -49,17 +49,17 @@ bool RenderPass::AddCommand(Command command) { } } - if (command.index_count == 0u) { - // Essentially a no-op. Don't record the command but this is not necessary - // an error either. - return true; - } - - if (command.instance_count == 0u) { - // Essentially a no-op. Don't record the command but this is not necessary - // an error either. - return true; - } + // if (command.index_count == 0u) { + // // Essentially a no-op. Don't record the command but this is not necessary + // // an error either. + // return true; + // } + + // if (command.instance_count == 0u) { + // // Essentially a no-op. Don't record the command but this is not necessary + // // an error either. + // return true; + // } commands_.emplace_back(std::move(command)); return true; From 0fc1ee2e1babf999a3432cb3d5c2a6516824d534 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 11 May 2023 20:48:46 -0700 Subject: [PATCH 16/25] fix no index --- impeller/core/vertex_buffer.h | 3 ++- impeller/entity/geometry.cc | 2 +- .../renderer/backend/metal/render_pass_mtl.mm | 3 ++- impeller/renderer/render_pass.cc | 22 +++++++++---------- impeller/renderer/vertex_buffer_builder.h | 11 +++++++--- 5 files changed, 24 insertions(+), 17 deletions(-) diff --git a/impeller/core/vertex_buffer.h b/impeller/core/vertex_buffer.h index accb0f73e0f6c..bd5d0724d44fb 100644 --- a/impeller/core/vertex_buffer.h +++ b/impeller/core/vertex_buffer.h @@ -16,7 +16,8 @@ struct VertexBuffer { IndexType index_type = IndexType::kUnknown; constexpr operator bool() const { - return static_cast(vertex_buffer); // && static_cast(index_buffer); + return static_cast(vertex_buffer) && + (index_type == IndexType::kNone || static_cast(index_buffer)); } }; diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index 30c0668a626f9..9bac96a8a11af 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -897,7 +897,7 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( .vertex_buffer = {.vertex_buffer = {.buffer = buffer, .range = Range{0, total * sizeof(Point)}}, - .index_count = divisions_per_circle * points_.size() * 3, + .index_count = total, .index_type = IndexType::kNone}, .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * entity.GetTransformation(), diff --git a/impeller/renderer/backend/metal/render_pass_mtl.mm b/impeller/renderer/backend/metal/render_pass_mtl.mm index 3cd982ed6b8ca..76ef6b51afeda 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.mm +++ b/impeller/renderer/backend/metal/render_pass_mtl.mm @@ -489,10 +489,11 @@ static bool Bind(PassBindingsCache& pass, const PrimitiveType primitive_type = pipeline_desc.GetPrimitiveType(); if (command.index_type == IndexType::kNone) { + auto vtx_buffer = command.GetVertexBuffer(); [encoder drawPrimitives:ToMTLPrimitiveType(primitive_type) vertexStart:command.base_vertex vertexCount:command.index_count]; - return true; + continue; } if (command.index_type == IndexType::kUnknown) { diff --git a/impeller/renderer/render_pass.cc b/impeller/renderer/render_pass.cc index f46855f1daad9..d4e0bde02908a 100644 --- a/impeller/renderer/render_pass.cc +++ b/impeller/renderer/render_pass.cc @@ -49,17 +49,17 @@ bool RenderPass::AddCommand(Command command) { } } - // if (command.index_count == 0u) { - // // Essentially a no-op. Don't record the command but this is not necessary - // // an error either. - // return true; - // } - - // if (command.instance_count == 0u) { - // // Essentially a no-op. Don't record the command but this is not necessary - // // an error either. - // return true; - // } + if (command.index_count == 0u) { + // Essentially a no-op. Don't record the command but this is not necessary + // an error either. + return true; + } + + if (command.instance_count == 0u) { + // Essentially a no-op. Don't record the command but this is not necessary + // an error either. + return true; + } commands_.emplace_back(std::move(command)); return true; diff --git a/impeller/renderer/vertex_buffer_builder.h b/impeller/renderer/vertex_buffer_builder.h index c49387830f7ad..35d1b5d773c25 100644 --- a/impeller/renderer/vertex_buffer_builder.h +++ b/impeller/renderer/vertex_buffer_builder.h @@ -75,9 +75,14 @@ class VertexBufferBuilder { VertexBuffer CreateVertexBuffer(HostBuffer& host_buffer) const { VertexBuffer buffer; buffer.vertex_buffer = CreateVertexBufferView(host_buffer); - buffer.index_buffer = CreateIndexBufferView(host_buffer); - buffer.index_count = GetIndexCount(); - buffer.index_type = GetIndexType(); + if (indices_.size() == 0) { + buffer.index_count = GetVertexCount(); + buffer.index_type = impeller::IndexType::kNone; + } else { + buffer.index_buffer = CreateIndexBufferView(host_buffer); + buffer.index_count = GetIndexCount(); + buffer.index_type = GetIndexType(); + } return buffer; }; From 6d979a2c4be85c8c786e917215e3d680f0e19694 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 11 May 2023 20:49:08 -0700 Subject: [PATCH 17/25] ++ --- impeller/renderer/backend/metal/render_pass_mtl.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/impeller/renderer/backend/metal/render_pass_mtl.mm b/impeller/renderer/backend/metal/render_pass_mtl.mm index 76ef6b51afeda..7fb64a7e1bea0 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.mm +++ b/impeller/renderer/backend/metal/render_pass_mtl.mm @@ -491,8 +491,8 @@ static bool Bind(PassBindingsCache& pass, if (command.index_type == IndexType::kNone) { auto vtx_buffer = command.GetVertexBuffer(); [encoder drawPrimitives:ToMTLPrimitiveType(primitive_type) - vertexStart:command.base_vertex - vertexCount:command.index_count]; + vertexStart:command.base_vertex + vertexCount:command.index_count]; continue; } From a2f218d4d565f6f2c1bd406e8b74c390ab834458 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 11 May 2023 22:16:49 -0700 Subject: [PATCH 18/25] ++ --- impeller/renderer/vertex_buffer_builder.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/impeller/renderer/vertex_buffer_builder.h b/impeller/renderer/vertex_buffer_builder.h index e482882f58dd4..a84bb39d8b35f 100644 --- a/impeller/renderer/vertex_buffer_builder.h +++ b/impeller/renderer/vertex_buffer_builder.h @@ -75,20 +75,9 @@ class VertexBufferBuilder { VertexBuffer CreateVertexBuffer(HostBuffer& host_buffer) const { VertexBuffer buffer; buffer.vertex_buffer = CreateVertexBufferView(host_buffer); -<<<<<<< HEAD - if (indices_.size() == 0) { - buffer.index_count = GetVertexCount(); - buffer.index_type = impeller::IndexType::kNone; - } else { - buffer.index_buffer = CreateIndexBufferView(host_buffer); - buffer.index_count = GetIndexCount(); - buffer.index_type = GetIndexType(); - } -======= buffer.index_buffer = CreateIndexBufferView(host_buffer); buffer.vertex_count = GetIndexCount(); buffer.index_type = GetIndexType(); ->>>>>>> 3e608274c9526b7707c8f3798d41f6e937e386f7 return buffer; }; From cbb0aa64d5d13c16f42b1f13bfd6df1aff16ca57 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 12 May 2023 09:02:16 -0700 Subject: [PATCH 19/25] Rename field --- impeller/entity/geometry.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index 9278bbe71cea2..d4110168f0124 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -838,7 +838,7 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( auto vtx_buffer = VertexBuffer{ .vertex_buffer = host_buffer.Emplace( points_.data(), points_.size() * sizeof(Point), alignof(Point)), - .index_count = points_.size(), + .vertex_count = points_.size(), .index_type = IndexType::kNone, }; @@ -891,7 +891,7 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( .vertex_buffer = {.vertex_buffer = {.buffer = buffer, .range = Range{0, total * sizeof(Point)}}, - .index_count = total, + .vertex_count = total, .index_type = IndexType::kNone}, .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * entity.GetTransformation(), From 87997950c7f05186f76620db80ad0b4a62e8eec9 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 12 May 2023 11:01:44 -0700 Subject: [PATCH 20/25] improve efficiency --- impeller/base/validation.cc | 2 +- impeller/entity/geometry.cc | 42 ++++++++++++-------- impeller/entity/shaders/geometry/points.vert | 14 ++++--- impeller/renderer/render_target.h | 10 ++--- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/impeller/base/validation.cc b/impeller/base/validation.cc index d3a7031622fef..b58e42875c9bd 100644 --- a/impeller/base/validation.cc +++ b/impeller/base/validation.cc @@ -11,7 +11,7 @@ namespace impeller { static std::atomic_int32_t sValidationLogsDisabledCount = 0; -static bool sValidationLogsAreFatal = false; +static bool sValidationLogsAreFatal = true; void ImpellerValidationErrorsSetFatal(bool fatal) { sValidationLogsAreFatal = fatal; diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index 55f3fc870942b..eb8b0630603b0 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -830,7 +830,8 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( auto divisions_per_circle = ComputeCircleDivisions( entity.GetTransformation().GetMaxBasisLength() * radius_, round_); - auto total = divisions_per_circle * points_.size() * 3; + auto points_per_circle = (divisions_per_circle - 2) * 3; + auto total = points_per_circle * points_.size(); auto& host_buffer = pass.GetTransientsBuffer(); using VS = PointFieldGeometryPipeline::VertexShader; @@ -857,13 +858,14 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( options.stencil_compare = CompareFunction::kAlways; options.stencil_operation = StencilOperation::kKeep; options.enable_rasterization = false; + options.sample_count = SampleCount::kCount1; cmd.pipeline = renderer.GetPointFieldGeometryPipeline(options); VS::FrameInfo frame_info; frame_info.radius = radius_; frame_info.radian_start = round_ ? 0.0f : 0.785398f; frame_info.radian_step = k2Pi / divisions_per_circle; - frame_info.points_per_circle = divisions_per_circle * 3; + frame_info.points_per_circle = points_per_circle; frame_info.divisions_per_circle = divisions_per_circle; VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); @@ -912,35 +914,41 @@ GeometryResult PointFieldGeometry::GetPositionBufferCPU( RenderPass& pass) { auto divisions_per_circle = ComputeCircleDivisions( entity.GetTransformation().GetMaxBasisLength() * radius_, round_); - auto total = divisions_per_circle * points_.size() * 3; + auto points_per_circle = (divisions_per_circle - 2) * 3; + auto total = points_per_circle * points_.size(); auto& host_buffer = pass.GetTransientsBuffer(); auto radian_start = round_ ? 0.0f : 0.785398f; auto radian_step = k2Pi / divisions_per_circle; - VertexBufferBuilder - vtx_builder; + VertexBufferBuilder vtx_builder; vtx_builder.Reserve(total); + /// Precompute all relative points and angles for a fixed geometry size. + auto elapsed_angle = radian_start; + std::vector angle_table(divisions_per_circle + 1); + for (auto i = 0u; i < divisions_per_circle + 1; i++) { + angle_table[i] = Point(cos(elapsed_angle), sin(elapsed_angle)) * radius_; + elapsed_angle += radian_step; + } + for (auto i = 0u; i < points_.size(); i++) { - auto elapsed_angle = radian_start; auto center = points_[i]; - vtx_builder.AppendVertex({center}); + auto j = 0u; + + auto origin = center + angle_table[j++]; + vtx_builder.AppendVertex({origin}); - auto pt1 = center + Point(cos(elapsed_angle), sin(elapsed_angle)) * radius_; + auto pt1 = center + angle_table[j++]; vtx_builder.AppendVertex({pt1}); - elapsed_angle += radian_step; - auto pt2 = center + Point(cos(elapsed_angle), sin(elapsed_angle)) * radius_; + auto pt2 = center + angle_table[j++]; vtx_builder.AppendVertex({pt2}); - for (auto j = 0u; j < divisions_per_circle - 1; j++) { - vtx_builder.AppendVertex({center}); - - pt1 = pt2; - elapsed_angle += radian_step; - vtx_builder.AppendVertex({pt1}); + for (auto j = 0u; j < divisions_per_circle - 2; j++) { + vtx_builder.AppendVertex({origin}); + vtx_builder.AppendVertex({pt2}); - pt2 = center + Point(cos(elapsed_angle), sin(elapsed_angle)) * radius_; + pt2 = center + angle_table[j++]; vtx_builder.AppendVertex({pt2}); } } diff --git a/impeller/entity/shaders/geometry/points.vert b/impeller/entity/shaders/geometry/points.vert index 5e3a748b6e353..9e4ba05f9a13c 100644 --- a/impeller/entity/shaders/geometry/points.vert +++ b/impeller/entity/shaders/geometry/points.vert @@ -27,8 +27,12 @@ void main() { int bufer_offset = gl_VertexIndex * frame_info.points_per_circle; float16_t elapsed_angle = frame_info.radian_start; - geometry_data.geometry[bufer_offset++] = center; + vec2 origin = + center + vec2(cos(elapsed_angle), sin(elapsed_angle)) * frame_info.radius; + geometry_data.geometry[bufer_offset++] = origin; + + elapsed_angle += frame_info.radian_step; vec2 pt1 = center + vec2(cos(elapsed_angle), sin(elapsed_angle)) * frame_info.radius; geometry_data.geometry[bufer_offset++] = pt1; @@ -38,13 +42,11 @@ void main() { center + vec2(cos(elapsed_angle), sin(elapsed_angle)) * frame_info.radius; geometry_data.geometry[bufer_offset++] = pt2; - for (int i = 1; i < frame_info.divisions_per_circle; i++) { - geometry_data.geometry[bufer_offset++] = center; + for (int i = 0; i < frame_info.divisions_per_circle - 2; i++) { + geometry_data.geometry[bufer_offset++] = origin; + geometry_data.geometry[bufer_offset++] = pt2; - pt1 = pt2; elapsed_angle += frame_info.radian_step; - geometry_data.geometry[bufer_offset++] = pt1; - pt2 = center + vec2(cos(elapsed_angle), sin(elapsed_angle)) * frame_info.radius; geometry_data.geometry[bufer_offset++] = pt2; diff --git a/impeller/renderer/render_target.h b/impeller/renderer/render_target.h index 4bd783c5c626c..2b44a3c9445e0 100644 --- a/impeller/renderer/render_target.h +++ b/impeller/renderer/render_target.h @@ -53,11 +53,11 @@ class RenderTarget final { .store_action = StoreAction::kDontCare, .clear_color = Color::BlackTransparent()}; - static constexpr AttachmentConfig kDefaultColorAttachmentConfigNonRendering = { - .storage_mode = StorageMode::kDevicePrivate, - .load_action = LoadAction::kDontCare, - .store_action = StoreAction::kDontCare, - .clear_color = Color::BlackTransparent()}; + static constexpr AttachmentConfig kDefaultColorAttachmentConfigNonRendering = + {.storage_mode = StorageMode::kDevicePrivate, + .load_action = LoadAction::kDontCare, + .store_action = StoreAction::kDontCare, + .clear_color = Color::BlackTransparent()}; static RenderTarget CreateOffscreen( const Context& context, From b715d4099132bd7ae6374bedf3b9046d0addc137 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 12 May 2023 12:04:18 -0700 Subject: [PATCH 21/25] ++ --- impeller/aiks/canvas.cc | 3 ++ impeller/display_list/dl_dispatcher.cc | 8 ++- impeller/entity/geometry.cc | 51 +++++++++++--------- impeller/entity/geometry.h | 3 +- impeller/entity/shaders/geometry/points.vert | 2 +- 5 files changed, 41 insertions(+), 26 deletions(-) diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 0b04493d7a43a..c13520f74e4d3 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -387,6 +387,9 @@ void Canvas::DrawPoints(std::vector points, Scalar radius, const Paint& paint, PointStyle point_style) { + if (radius <= 0) { + return; + } Entity entity; entity.SetTransformation(GetCurrentTransformation()); entity.SetStencilDepth(GetStencilDepth()); diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index fdb8ffd2bab24..8adaa55c1e2b8 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -934,8 +934,12 @@ void DlDispatcher::drawPoints(PointMode mode, // Cap::kButt is also treated as a square. auto point_style = paint.stroke_cap == Cap::kRound ? PointStyle::kRound : PointStyle::kSquare; - canvas_.DrawPoints(skia_conversions::ToPoints(points, count), - paint.stroke_width / 2.0, paint, point_style); + auto radius = paint.stroke_width; + if (radius > 0) { + radius /= 2.0; + } + canvas_.DrawPoints(skia_conversions::ToPoints(points, count), radius, + paint, point_style); } break; case flutter::DlCanvas::PointMode::kLines: for (uint32_t i = 1; i < count; i += 2) { diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index eb8b0630603b0..d5516d5fea972 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -820,17 +820,24 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( const ContentContext& renderer, const Entity& entity, RenderPass& pass) { - if (radius_ <= 0) { + if (radius_ < 0.0) { + return {}; + } + auto determinant = entity.GetTransformation().GetDeterminant(); + if (determinant == 0) { return {}; } + Scalar min_size = 1.0f / sqrt(std::abs(determinant)); + Scalar radius = std::max(radius_, min_size); + if (!renderer.GetDeviceCapabilities().SupportsDisabledRasterization()) { - return GetPositionBufferCPU(renderer, entity, pass); + return GetPositionBufferCPU(renderer, entity, pass, radius); } - auto divisions_per_circle = ComputeCircleDivisions( - entity.GetTransformation().GetMaxBasisLength() * radius_, round_); - auto points_per_circle = (divisions_per_circle - 2) * 3; + auto vertices_per_geom = ComputeCircleDivisions( + entity.GetTransformation().GetMaxBasisLength() * radius, round_); + auto points_per_circle = 3 + (vertices_per_geom - 3) * 3; auto total = points_per_circle * points_.size(); auto& host_buffer = pass.GetTransientsBuffer(); @@ -862,11 +869,11 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( cmd.pipeline = renderer.GetPointFieldGeometryPipeline(options); VS::FrameInfo frame_info; - frame_info.radius = radius_; + frame_info.radius = radius; frame_info.radian_start = round_ ? 0.0f : 0.785398f; - frame_info.radian_step = k2Pi / divisions_per_circle; + frame_info.radian_step = k2Pi / vertices_per_geom; frame_info.points_per_circle = points_per_circle; - frame_info.divisions_per_circle = divisions_per_circle; + frame_info.divisions_per_circle = vertices_per_geom; VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); VS::BindGeometryData( @@ -911,44 +918,44 @@ GeometryResult PointFieldGeometry::GetPositionBuffer( GeometryResult PointFieldGeometry::GetPositionBufferCPU( const ContentContext& renderer, const Entity& entity, - RenderPass& pass) { - auto divisions_per_circle = ComputeCircleDivisions( - entity.GetTransformation().GetMaxBasisLength() * radius_, round_); - auto points_per_circle = (divisions_per_circle - 2) * 3; + RenderPass& pass, + Scalar radius) { + auto vertices_per_geom = ComputeCircleDivisions( + entity.GetTransformation().GetMaxBasisLength() * radius, round_); + auto points_per_circle = 3 + (vertices_per_geom - 3) * 3; auto total = points_per_circle * points_.size(); auto& host_buffer = pass.GetTransientsBuffer(); auto radian_start = round_ ? 0.0f : 0.785398f; - auto radian_step = k2Pi / divisions_per_circle; + auto radian_step = k2Pi / vertices_per_geom; VertexBufferBuilder vtx_builder; vtx_builder.Reserve(total); /// Precompute all relative points and angles for a fixed geometry size. auto elapsed_angle = radian_start; - std::vector angle_table(divisions_per_circle + 1); - for (auto i = 0u; i < divisions_per_circle + 1; i++) { - angle_table[i] = Point(cos(elapsed_angle), sin(elapsed_angle)) * radius_; + std::vector angle_table(vertices_per_geom); + for (auto i = 0u; i < vertices_per_geom; i++) { + angle_table[i] = Point(cos(elapsed_angle), sin(elapsed_angle)) * radius; elapsed_angle += radian_step; } for (auto i = 0u; i < points_.size(); i++) { auto center = points_[i]; - auto j = 0u; - auto origin = center + angle_table[j++]; + auto origin = center + angle_table[0]; vtx_builder.AppendVertex({origin}); - auto pt1 = center + angle_table[j++]; + auto pt1 = center + angle_table[1]; vtx_builder.AppendVertex({pt1}); - auto pt2 = center + angle_table[j++]; + auto pt2 = center + angle_table[2]; vtx_builder.AppendVertex({pt2}); - for (auto j = 0u; j < divisions_per_circle - 2; j++) { + for (auto j = 0u; j < vertices_per_geom - 3; j++) { vtx_builder.AppendVertex({origin}); vtx_builder.AppendVertex({pt2}); - pt2 = center + angle_table[j++]; + pt2 = center + angle_table[j + 3]; vtx_builder.AppendVertex({pt2}); } } diff --git a/impeller/entity/geometry.h b/impeller/entity/geometry.h index 6937d173e7bc2..cac8007a6ba58 100644 --- a/impeller/entity/geometry.h +++ b/impeller/entity/geometry.h @@ -293,7 +293,8 @@ class PointFieldGeometry : public Geometry { GeometryResult GetPositionBufferCPU(const ContentContext& renderer, const Entity& entity, - RenderPass& pass); + RenderPass& pass, + Scalar radius); std::vector points_; Scalar radius_; diff --git a/impeller/entity/shaders/geometry/points.vert b/impeller/entity/shaders/geometry/points.vert index 9e4ba05f9a13c..6e8910cb917c9 100644 --- a/impeller/entity/shaders/geometry/points.vert +++ b/impeller/entity/shaders/geometry/points.vert @@ -42,7 +42,7 @@ void main() { center + vec2(cos(elapsed_angle), sin(elapsed_angle)) * frame_info.radius; geometry_data.geometry[bufer_offset++] = pt2; - for (int i = 0; i < frame_info.divisions_per_circle - 2; i++) { + for (int i = 0; i < frame_info.divisions_per_circle - 3; i++) { geometry_data.geometry[bufer_offset++] = origin; geometry_data.geometry[bufer_offset++] = pt2; From 769392586cb428afd22944b961548f41d4852cff Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 12 May 2023 15:55:45 -0700 Subject: [PATCH 22/25] disable on desktop --- impeller/renderer/backend/metal/context_mtl.mm | 13 ++++++++++++- impeller/renderer/backend/vulkan/render_pass_vk.cc | 1 - 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/impeller/renderer/backend/metal/context_mtl.mm b/impeller/renderer/backend/metal/context_mtl.mm index 12862b76f81e3..e37757e44195d 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -45,6 +45,17 @@ static bool DeviceSupportsComputeSubgroups(id device) { return supports_subgroups; } +static bool SupportsDisabledRasterization() { + // TOOD(jonahwilliams): on macOS playgrounds there seems to be some alignment + // issues with the device buffers but I haven't been able to trigger any sort + // of validation warnings. Disabling there for now. +#if FML_OS_IOS + return true; +#else + return false; +#endif // FML_OS_IOS +} + static std::unique_ptr InferMetalCapabilities( id device, PixelFormat color_format) { @@ -62,7 +73,7 @@ static bool DeviceSupportsComputeSubgroups(id device) { .SetSupportsComputeSubgroups(DeviceSupportsComputeSubgroups(device)) .SetSupportsReadFromResolve(true) .SetSupportsReadFromOnscreenTexture(true) - .SetSupportsDisabledRasterization(true) + .SetSupportsDisabledRasterization(SupportsDisabledRasterization()) .Build(); } diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.cc b/impeller/renderer/backend/vulkan/render_pass_vk.cc index 87a201eae43df..40c8da7fe8420 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -522,7 +522,6 @@ static bool EncodeCommand(const Context& context, 0u // first instance ); } else { - FML_LOG(ERROR) << "HERE!!!"; cmd_buffer.draw(command.vertex_count, // vertex count command.instance_count, // instance count command.base_vertex, // vertex offset From 6f46186f5eedd71a7737f5c8c9a5a4b4b4025778 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 12 May 2023 19:14:27 -0700 Subject: [PATCH 23/25] fix geometry computation bug --- impeller/aiks/canvas.cc | 1 + impeller/entity/geometry.cc | 21 +++++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index c13520f74e4d3..6ac4df2f0d4fe 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -390,6 +390,7 @@ void Canvas::DrawPoints(std::vector points, if (radius <= 0) { return; } + Entity entity; entity.SetTransformation(GetCurrentTransformation()); entity.SetStencilDepth(GetStencilDepth()); diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index d5516d5fea972..e24b324f6bf44 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "impeller/entity/geometry.h" -#include #include "impeller/core/device_buffer.h" #include "impeller/entity/contents/content_context.h" @@ -1012,9 +1011,23 @@ GeometryVertexType PointFieldGeometry::GetVertexType() const { // |Geometry| std::optional PointFieldGeometry::GetCoverage( const Matrix& transform) const { - auto pt_bounds = Rect::MakePointBounds(points_.begin(), points_.end()); - if (pt_bounds.has_value()) { - return pt_bounds->TransformBounds(transform); + if (points_.size() > 0) { + // Doesn't use MakePointBounds as this isn't resilient to points that + // lie along the same axis. + auto first = points_.begin(); + auto last = points_.end(); + auto left = first->x; + auto top = first->y; + auto right = first->x; + auto bottom = first->y; + for (auto it = first + 1; it < last; ++it) { + left = std::min(left, it->x); + top = std::min(top, it->y); + right = std::max(right, it->x); + bottom = std::max(bottom, it->y); + } + return Rect::MakeLTRB(left - radius_, top - radius_, right + radius_, + bottom + radius_); } return std::nullopt; } From cca59fee692ec40679274c634695f0342dac273c Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 12 May 2023 19:45:38 -0700 Subject: [PATCH 24/25] malioc update --- impeller/tools/malioc.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/impeller/tools/malioc.json b/impeller/tools/malioc.json index c542644d07ae8..2361bcb96c997 100644 --- a/impeller/tools/malioc.json +++ b/impeller/tools/malioc.json @@ -12075,7 +12075,7 @@ "type": "Vertex", "variants": { "Position": { - "fp16_arithmetic": 30, + "fp16_arithmetic": 35, "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ @@ -12102,7 +12102,7 @@ ], "shortest_path_cycles": [ 0.203125, - 0.03125, + 0.046875, 0.203125, 0.0625, 3.0, @@ -12113,7 +12113,7 @@ ], "total_cycles": [ 0.375, - 0.203125, + 0.21875, 0.375, 0.1875, 5.0, @@ -12122,7 +12122,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 12, + "uniform_registers_used": 14, "work_registers_used": 17 } } From f08fff2fff23b1421fe7ffad6c331bb8c1226b59 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 12 May 2023 19:50:11 -0700 Subject: [PATCH 25/25] ++ --- impeller/base/validation.cc | 2 +- impeller/renderer/backend/metal/render_pass_mtl.mm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/impeller/base/validation.cc b/impeller/base/validation.cc index b58e42875c9bd..d3a7031622fef 100644 --- a/impeller/base/validation.cc +++ b/impeller/base/validation.cc @@ -11,7 +11,7 @@ namespace impeller { static std::atomic_int32_t sValidationLogsDisabledCount = 0; -static bool sValidationLogsAreFatal = true; +static bool sValidationLogsAreFatal = false; void ImpellerValidationErrorsSetFatal(bool fatal) { sValidationLogsAreFatal = fatal; diff --git a/impeller/renderer/backend/metal/render_pass_mtl.mm b/impeller/renderer/backend/metal/render_pass_mtl.mm index 003212e33e5e2..1eb63299b23fb 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.mm +++ b/impeller/renderer/backend/metal/render_pass_mtl.mm @@ -3,7 +3,7 @@ // found in the LICENSE file. #include "impeller/renderer/backend/metal/render_pass_mtl.h" -#include + #include "flutter/fml/closure.h" #include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h"