From c81fbbdac72daf453a711593fe01ab6e80f87181 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Wed, 2 Mar 2022 17:22:51 -0800 Subject: [PATCH] Move Contents classes into separate translation units (#53) --- impeller/aiks/aiks_context.h | 2 +- impeller/aiks/canvas.cc | 3 + impeller/aiks/canvas.h | 1 + impeller/aiks/paint.cc | 2 + impeller/aiks/paint.h | 2 +- impeller/aiks/paint_pass_delegate.cc | 3 +- .../display_list/display_list_dispatcher.cc | 1 + impeller/entity/BUILD.gn | 20 +- impeller/entity/contents.cc | 826 ------------------ impeller/entity/contents.h | 248 ------ impeller/entity/contents/clip_contents.cc | 88 ++ impeller/entity/contents/clip_contents.h | 51 ++ .../entity/{ => contents}/content_context.cc | 2 +- .../entity/{ => contents}/content_context.h | 64 +- impeller/entity/contents/contents.cc | 22 + impeller/entity/contents/contents.h | 37 + .../contents/linear_gradient_contents.cc | 79 ++ .../contents/linear_gradient_contents.h | 43 + .../entity/contents/solid_color_contents.cc | 83 ++ .../entity/contents/solid_color_contents.h | 47 + .../entity/contents/solid_stroke_contents.cc | 358 ++++++++ .../entity/contents/solid_stroke_contents.h | 92 ++ impeller/entity/contents/text_contents.cc | 134 +++ impeller/entity/contents/text_contents.h | 45 + impeller/entity/contents/texture_contents.cc | 115 +++ impeller/entity/contents/texture_contents.h | 48 + impeller/entity/entity.cc | 2 +- impeller/entity/entity.h | 2 +- impeller/entity/entity_pass.cc | 2 +- impeller/entity/entity_pass.h | 2 +- impeller/entity/entity_pass_delegate.h | 2 +- impeller/entity/entity_playground.cc | 2 +- impeller/entity/entity_playground.h | 2 +- impeller/entity/entity_unittests.cc | 3 +- 34 files changed, 1315 insertions(+), 1118 deletions(-) delete mode 100644 impeller/entity/contents.cc delete mode 100644 impeller/entity/contents.h create mode 100644 impeller/entity/contents/clip_contents.cc create mode 100644 impeller/entity/contents/clip_contents.h rename impeller/entity/{ => contents}/content_context.cc (98%) rename impeller/entity/{ => contents}/content_context.h (72%) create mode 100644 impeller/entity/contents/contents.cc create mode 100644 impeller/entity/contents/contents.h create mode 100644 impeller/entity/contents/linear_gradient_contents.cc create mode 100644 impeller/entity/contents/linear_gradient_contents.h create mode 100644 impeller/entity/contents/solid_color_contents.cc create mode 100644 impeller/entity/contents/solid_color_contents.h create mode 100644 impeller/entity/contents/solid_stroke_contents.cc create mode 100644 impeller/entity/contents/solid_stroke_contents.h create mode 100644 impeller/entity/contents/text_contents.cc create mode 100644 impeller/entity/contents/text_contents.h create mode 100644 impeller/entity/contents/texture_contents.cc create mode 100644 impeller/entity/contents/texture_contents.h diff --git a/impeller/aiks/aiks_context.h b/impeller/aiks/aiks_context.h index edbdd604a491a..cbdd93ea2e2de 100644 --- a/impeller/aiks/aiks_context.h +++ b/impeller/aiks/aiks_context.h @@ -7,7 +7,7 @@ #include #include "flutter/fml/macros.h" -#include "impeller/entity/content_context.h" +#include "impeller/entity/contents/content_context.h" #include "impeller/renderer/context.h" namespace impeller { diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index f9c19fe3cc2d4..311655ffdfaa6 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -8,6 +8,9 @@ #include "flutter/fml/logging.h" #include "impeller/aiks/paint_pass_delegate.h" +#include "impeller/entity/contents/clip_contents.h" +#include "impeller/entity/contents/text_contents.h" +#include "impeller/entity/contents/texture_contents.h" #include "impeller/geometry/path_builder.h" namespace impeller { diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index 56a23aaa9426e..0dc6d810924b7 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -18,6 +18,7 @@ #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" #include "impeller/geometry/vector.h" +#include "impeller/typographer/glyph_atlas.h" #include "impeller/typographer/text_frame.h" namespace impeller { diff --git a/impeller/aiks/paint.cc b/impeller/aiks/paint.cc index 6f2eea50cce7d..06de4e6399f9a 100644 --- a/impeller/aiks/paint.cc +++ b/impeller/aiks/paint.cc @@ -3,6 +3,8 @@ // found in the LICENSE file. #include "impeller/aiks/paint.h" +#include "impeller/entity/contents/solid_color_contents.h" +#include "impeller/entity/contents/solid_stroke_contents.h" namespace impeller { diff --git a/impeller/aiks/paint.h b/impeller/aiks/paint.h index 7a941474a7125..35ef71b7fccd1 100644 --- a/impeller/aiks/paint.h +++ b/impeller/aiks/paint.h @@ -7,7 +7,7 @@ #include #include "flutter/fml/macros.h" -#include "impeller/entity/contents.h" +#include "impeller/entity/contents/contents.h" #include "impeller/geometry/color.h" namespace impeller { diff --git a/impeller/aiks/paint_pass_delegate.cc b/impeller/aiks/paint_pass_delegate.cc index f0f09cd5c674a..f17ba655540cf 100644 --- a/impeller/aiks/paint_pass_delegate.cc +++ b/impeller/aiks/paint_pass_delegate.cc @@ -4,7 +4,8 @@ #include "impeller/aiks/paint_pass_delegate.h" -#include "impeller/entity/contents.h" +#include "impeller/entity/contents/contents.h" +#include "impeller/entity/contents/texture_contents.h" namespace impeller { diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index ddeabcffa3739..a8e500ac89c23 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -5,6 +5,7 @@ #include "impeller/display_list/display_list_dispatcher.h" #include "flutter/fml/trace_event.h" +#include "impeller/entity/contents/linear_gradient_contents.h" #include "impeller/geometry/path_builder.h" #include "impeller/typographer/backends/skia/text_frame_skia.h" #include "third_party/skia/include/core/SkColor.h" diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 6a01accfba421..0181edfd2c34f 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -23,10 +23,22 @@ impeller_shaders("entity_shaders") { impeller_component("entity") { sources = [ - "content_context.cc", - "content_context.h", - "contents.cc", - "contents.h", + "contents/clip_contents.cc", + "contents/clip_contents.h", + "contents/content_context.cc", + "contents/content_context.h", + "contents/contents.cc", + "contents/contents.h", + "contents/linear_gradient_contents.cc", + "contents/linear_gradient_contents.h", + "contents/solid_color_contents.cc", + "contents/solid_color_contents.h", + "contents/solid_stroke_contents.cc", + "contents/solid_stroke_contents.h", + "contents/text_contents.cc", + "contents/text_contents.h", + "contents/texture_contents.cc", + "contents/texture_contents.h", "entity.cc", "entity.h", "entity_pass.cc", diff --git a/impeller/entity/contents.cc b/impeller/entity/contents.cc deleted file mode 100644 index a1f5bcfa789a4..0000000000000 --- a/impeller/entity/contents.cc +++ /dev/null @@ -1,826 +0,0 @@ -// 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 "impeller/entity/contents.h" - -#include -#include - -#include "flutter/fml/logging.h" -#include "impeller/entity/content_context.h" -#include "impeller/entity/entity.h" -#include "impeller/geometry/path_builder.h" -#include "impeller/geometry/path_component.h" -#include "impeller/geometry/scalar.h" -#include "impeller/geometry/vector.h" -#include "impeller/renderer/render_pass.h" -#include "impeller/renderer/sampler_library.h" -#include "impeller/renderer/surface.h" -#include "impeller/renderer/tessellator.h" -#include "impeller/renderer/vertex_buffer.h" -#include "impeller/renderer/vertex_buffer_builder.h" - -namespace impeller { - -static ContentContext::Options OptionsFromPass(const RenderPass& pass) { - ContentContext::Options opts; - opts.sample_count = pass.GetRenderTarget().GetSampleCount(); - return opts; -} - -/******************************************************************************* - ******* Contents - ******************************************************************************/ - -Contents::Contents() = default; - -Contents::~Contents() = default; - -/******************************************************************************* - ******* Linear Gradient Contents - ******************************************************************************/ - -LinearGradientContents::LinearGradientContents() = default; - -LinearGradientContents::~LinearGradientContents() = default; - -void LinearGradientContents::SetEndPoints(Point start_point, Point end_point) { - start_point_ = start_point; - end_point_ = end_point; -} - -void LinearGradientContents::SetColors(std::vector colors) { - colors_ = std::move(colors); - if (colors_.empty()) { - colors_.push_back(Color::Black()); - colors_.push_back(Color::Black()); - } else if (colors_.size() < 2u) { - colors_.push_back(colors_.back()); - } -} - -const std::vector& LinearGradientContents::GetColors() const { - return colors_; -} - -bool LinearGradientContents::Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { - using VS = GradientFillPipeline::VertexShader; - using FS = GradientFillPipeline::FragmentShader; - - auto vertices_builder = VertexBufferBuilder(); - { - auto result = Tessellator{entity.GetPath().GetFillType()}.Tessellate( - entity.GetPath().CreatePolyline(), [&vertices_builder](Point point) { - VS::PerVertexData vtx; - vtx.vertices = point; - vertices_builder.AppendVertex(vtx); - }); - if (!result) { - return false; - } - } - - VS::FrameInfo frame_info; - frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * - entity.GetTransformation(); - - FS::GradientInfo gradient_info; - gradient_info.start_point = start_point_; - gradient_info.end_point = end_point_; - gradient_info.start_color = colors_[0]; - gradient_info.end_color = colors_[1]; - - Command cmd; - cmd.label = "LinearGradientFill"; - cmd.pipeline = renderer.GetGradientFillPipeline(OptionsFromPass(pass)); - cmd.stencil_reference = entity.GetStencilDepth(); - cmd.BindVertices( - vertices_builder.CreateVertexBuffer(pass.GetTransientsBuffer())); - cmd.primitive_type = PrimitiveType::kTriangle; - FS::BindGradientInfo( - cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); - VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); - return pass.AddCommand(std::move(cmd)); -} - -/******************************************************************************* - ******* SolidColorContents - ******************************************************************************/ - -SolidColorContents::SolidColorContents() = default; - -SolidColorContents::~SolidColorContents() = default; - -void SolidColorContents::SetColor(Color color) { - color_ = color; -} - -const Color& SolidColorContents::GetColor() const { - return color_; -} - -static VertexBuffer CreateSolidFillVertices(const Path& path, - HostBuffer& buffer) { - using VS = SolidFillPipeline::VertexShader; - - VertexBufferBuilder vtx_builder; - - auto tesselation_result = Tessellator{path.GetFillType()}.Tessellate( - path.CreatePolyline(), [&vtx_builder](auto point) { - VS::PerVertexData vtx; - vtx.vertices = point; - vtx_builder.AppendVertex(vtx); - }); - if (!tesselation_result) { - return {}; - } - - return vtx_builder.CreateVertexBuffer(buffer); -} - -bool SolidColorContents::Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { - if (color_.IsTransparent()) { - return true; - } - - using VS = SolidFillPipeline::VertexShader; - - Command cmd; - cmd.label = "SolidFill"; - cmd.pipeline = renderer.GetSolidFillPipeline(OptionsFromPass(pass)); - cmd.stencil_reference = entity.GetStencilDepth(); - cmd.BindVertices( - CreateSolidFillVertices(entity.GetPath(), pass.GetTransientsBuffer())); - - VS::FrameInfo frame_info; - frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * - entity.GetTransformation(); - frame_info.color = color_; - VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); - - cmd.primitive_type = PrimitiveType::kTriangle; - - if (!pass.AddCommand(std::move(cmd))) { - return false; - } - - return true; -} - -std::unique_ptr SolidColorContents::Make(Color color) { - auto contents = std::make_unique(); - contents->SetColor(color); - return contents; -} - -/******************************************************************************* - ******* TextureContents - ******************************************************************************/ - -TextureContents::TextureContents() = default; - -TextureContents::~TextureContents() = default; - -void TextureContents::SetTexture(std::shared_ptr texture) { - texture_ = std::move(texture); -} - -std::shared_ptr TextureContents::GetTexture() const { - return texture_; -} - -void TextureContents::SetOpacity(Scalar opacity) { - opacity_ = opacity; -} - -bool TextureContents::Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { - if (texture_ == nullptr) { - return true; - } - - using VS = TextureFillVertexShader; - using FS = TextureFillFragmentShader; - - const auto coverage_rect = entity.GetPath().GetBoundingBox(); - - if (!coverage_rect.has_value()) { - return true; - } - - if (coverage_rect->size.IsEmpty()) { - return true; - } - - const auto texture_size = texture_->GetSize(); - if (texture_size.IsEmpty()) { - return true; - } - - if (source_rect_.IsEmpty()) { - return true; - } - - VertexBufferBuilder vertex_builder; - { - const auto tess_result = - Tessellator{entity.GetPath().GetFillType()}.Tessellate( - entity.GetPath().CreatePolyline(), - [this, &vertex_builder, &coverage_rect, &texture_size](Point vtx) { - VS::PerVertexData data; - data.vertices = vtx; - auto coverage_coords = - (vtx - coverage_rect->origin) / coverage_rect->size; - data.texture_coords = - (source_rect_.origin + source_rect_.size * coverage_coords) / - texture_size; - vertex_builder.AppendVertex(data); - }); - if (!tess_result) { - return false; - } - } - - if (!vertex_builder.HasVertices()) { - return true; - } - - auto& host_buffer = pass.GetTransientsBuffer(); - - VS::FrameInfo frame_info; - frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * - entity.GetTransformation(); - frame_info.alpha = opacity_; - - Command cmd; - cmd.label = "TextureFill"; - cmd.pipeline = renderer.GetTexturePipeline(OptionsFromPass(pass)); - cmd.stencil_reference = entity.GetStencilDepth(); - cmd.BindVertices(vertex_builder.CreateVertexBuffer(host_buffer)); - VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); - FS::BindTextureSampler( - cmd, texture_, - renderer.GetContext()->GetSamplerLibrary()->GetSampler({})); - pass.AddCommand(std::move(cmd)); - - return true; -} - -void TextureContents::SetSourceRect(const IRect& source_rect) { - source_rect_ = source_rect; -} - -const IRect& TextureContents::GetSourceRect() const { - return source_rect_; -} - -/******************************************************************************* - ******* SolidStrokeContents - ******************************************************************************/ - -SolidStrokeContents::SolidStrokeContents() { - SetStrokeCap(Cap::kButt); - SetStrokeJoin(Join::kMiter); -} - -SolidStrokeContents::~SolidStrokeContents() = default; - -void SolidStrokeContents::SetColor(Color color) { - color_ = color; -} - -const Color& SolidStrokeContents::GetColor() const { - return color_; -} - -static VertexBuffer CreateSolidStrokeVertices( - const Path& path, - HostBuffer& buffer, - const SolidStrokeContents::CapProc& cap_proc, - const SolidStrokeContents::JoinProc& join_proc, - Scalar miter_limit, - const SmoothingApproximation& smoothing) { - using VS = SolidStrokeVertexShader; - - VertexBufferBuilder vtx_builder; - auto polyline = path.CreatePolyline(); - - if (polyline.points.size() < 2) { - return {}; // Nothing to render. - } - - VS::PerVertexData vtx; - - // Normal state. - Point normal; - Point previous_normal; // Used for computing joins. - - auto compute_normal = [&polyline, &normal, &previous_normal](size_t point_i) { - previous_normal = normal; - Point direction = - (polyline.points[point_i] - polyline.points[point_i - 1]).Normalize(); - normal = {-direction.y, direction.x}; - }; - - for (size_t contour_i = 0; contour_i < polyline.contours.size(); - contour_i++) { - size_t contour_start_point_i, contour_end_point_i; - std::tie(contour_start_point_i, contour_end_point_i) = - polyline.GetContourPointBounds(contour_i); - - if (contour_end_point_i - contour_start_point_i < 2) { - continue; // This contour has no renderable content. - } - - // The first point's normal is always the same as - compute_normal(contour_start_point_i + 1); - const Point contour_first_normal = normal; - - if (contour_i > 0) { - // This branch only executes when we've just finished drawing a contour - // and are switching to a new one. - // We're drawing a triangle strip, so we need to "pick up the pen" by - // appending transparent vertices between the end of the previous contour - // and the beginning of the new contour. - vtx.vertex_position = polyline.points[contour_start_point_i - 1]; - vtx.vertex_normal = {}; - vtx.pen_down = 0.0; - vtx_builder.AppendVertex(vtx); - vtx.vertex_position = polyline.points[contour_start_point_i]; - vtx_builder.AppendVertex(vtx); - } - - // Generate start cap. - if (!polyline.contours[contour_i].is_closed) { - cap_proc(vtx_builder, polyline.points[contour_start_point_i], -normal, - smoothing); - } - - // Generate contour geometry. - for (size_t point_i = contour_start_point_i; point_i < contour_end_point_i; - point_i++) { - if (point_i > contour_start_point_i) { - // Generate line rect. - vtx.vertex_position = polyline.points[point_i - 1]; - vtx.pen_down = 1.0; - vtx.vertex_normal = normal; - vtx_builder.AppendVertex(vtx); - vtx.vertex_normal = -normal; - vtx_builder.AppendVertex(vtx); - vtx.vertex_position = polyline.points[point_i]; - vtx.vertex_normal = normal; - vtx_builder.AppendVertex(vtx); - vtx.vertex_normal = -normal; - vtx_builder.AppendVertex(vtx); - - if (point_i < contour_end_point_i - 1) { - compute_normal(point_i + 1); - - // Generate join from the current line to the next line. - join_proc(vtx_builder, polyline.points[point_i], previous_normal, - normal, miter_limit, smoothing); - } - } - } - - // Generate end cap or join. - if (!polyline.contours[contour_i].is_closed) { - cap_proc(vtx_builder, polyline.points[contour_end_point_i - 1], normal, - smoothing); - } else { - join_proc(vtx_builder, polyline.points[contour_start_point_i], normal, - contour_first_normal, miter_limit, smoothing); - } - } - - return vtx_builder.CreateVertexBuffer(buffer); -} - -bool SolidStrokeContents::Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { - if (color_.IsTransparent() || stroke_size_ <= 0.0) { - return true; - } - - using VS = SolidStrokeVertexShader; - - VS::FrameInfo frame_info; - frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * - entity.GetTransformation(); - - VS::StrokeInfo stroke_info; - stroke_info.color = color_; - stroke_info.size = stroke_size_; - - Command cmd; - cmd.primitive_type = PrimitiveType::kTriangleStrip; - cmd.label = "SolidStroke"; - cmd.pipeline = renderer.GetSolidStrokePipeline(OptionsFromPass(pass)); - cmd.stencil_reference = entity.GetStencilDepth(); - cmd.BindVertices(CreateSolidStrokeVertices( - entity.GetPath(), pass.GetTransientsBuffer(), cap_proc_, join_proc_, - miter_limit_, arc_smoothing_approximation_)); - VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); - VS::BindStrokeInfo(cmd, - pass.GetTransientsBuffer().EmplaceUniform(stroke_info)); - - pass.AddCommand(std::move(cmd)); - - return true; -} - -void SolidStrokeContents::SetStrokeSize(Scalar size) { - stroke_size_ = size; - arc_smoothing_approximation_ = SmoothingApproximation(5.0 / size, 0.0, 0.0); -} - -Scalar SolidStrokeContents::GetStrokeSize() const { - return stroke_size_; -} - -void SolidStrokeContents::SetStrokeMiter(Scalar miter_limit) { - if (miter_limit < 0) { - return; // Skia behaves like this. - } - miter_limit_ = miter_limit; -} - -Scalar SolidStrokeContents::GetStrokeMiter() { - return miter_limit_; -} - -void SolidStrokeContents::SetStrokeCap(Cap cap) { - cap_ = cap; - - using VS = SolidStrokeVertexShader; - switch (cap) { - case Cap::kButt: - cap_proc_ = [](VertexBufferBuilder& vtx_builder, - const Point& position, const Point& normal, - const SmoothingApproximation& smoothing) {}; - break; - case Cap::kRound: - cap_proc_ = [](VertexBufferBuilder& vtx_builder, - const Point& position, const Point& normal, - const SmoothingApproximation& smoothing) { - SolidStrokeVertexShader::PerVertexData vtx; - vtx.vertex_position = position; - vtx.pen_down = 1.0; - - Point forward(normal.y, -normal.x); - - auto arc_points = - CubicPathComponent( - normal, normal + forward * PathBuilder::kArcApproximationMagic, - forward + normal * PathBuilder::kArcApproximationMagic, forward) - .CreatePolyline(smoothing); - - vtx.vertex_normal = normal; - vtx_builder.AppendVertex(vtx); - vtx.vertex_normal = -normal; - vtx_builder.AppendVertex(vtx); - for (const auto& point : arc_points) { - vtx.vertex_normal = point; - vtx_builder.AppendVertex(vtx); - vtx.vertex_normal = (-point).Reflect(forward); - vtx_builder.AppendVertex(vtx); - } - }; - break; - case Cap::kSquare: - cap_proc_ = [](VertexBufferBuilder& vtx_builder, - const Point& position, const Point& normal, - const SmoothingApproximation& smoothing) { - SolidStrokeVertexShader::PerVertexData vtx; - vtx.vertex_position = position; - vtx.pen_down = 1.0; - - Point forward(normal.y, -normal.x); - - vtx.vertex_normal = normal; - vtx_builder.AppendVertex(vtx); - vtx.vertex_normal = -normal; - vtx_builder.AppendVertex(vtx); - vtx.vertex_normal = normal + forward; - vtx_builder.AppendVertex(vtx); - vtx.vertex_normal = -normal + forward; - vtx_builder.AppendVertex(vtx); - }; - break; - } -} - -SolidStrokeContents::Cap SolidStrokeContents::GetStrokeCap() { - return cap_; -} - -static Scalar CreateBevelAndGetDirection( - VertexBufferBuilder& vtx_builder, - const Point& position, - const Point& start_normal, - const Point& end_normal) { - SolidStrokeVertexShader::PerVertexData vtx; - vtx.vertex_position = position; - vtx.pen_down = 1.0; - vtx.vertex_normal = {}; - vtx_builder.AppendVertex(vtx); - - Scalar dir = start_normal.Cross(end_normal) > 0 ? -1 : 1; - vtx.vertex_normal = start_normal * dir; - vtx_builder.AppendVertex(vtx); - vtx.vertex_normal = end_normal * dir; - vtx_builder.AppendVertex(vtx); - - return dir; -} - -void SolidStrokeContents::SetStrokeJoin(Join join) { - join_ = join; - - using VS = SolidStrokeVertexShader; - switch (join) { - case Join::kBevel: - join_proc_ = [](VertexBufferBuilder& vtx_builder, - const Point& position, const Point& start_normal, - const Point& end_normal, Scalar miter_limit, - const SmoothingApproximation& smoothing) { - CreateBevelAndGetDirection(vtx_builder, position, start_normal, - end_normal); - }; - break; - case Join::kMiter: - join_proc_ = [](VertexBufferBuilder& vtx_builder, - const Point& position, const Point& start_normal, - const Point& end_normal, Scalar miter_limit, - const SmoothingApproximation& smoothing) { - // 1 for no joint (straight line), 0 for max joint (180 degrees). - Scalar alignment = (start_normal.Dot(end_normal) + 1) / 2; - if (ScalarNearlyEqual(alignment, 1)) { - return; - } - - Scalar dir = CreateBevelAndGetDirection(vtx_builder, position, - start_normal, end_normal); - - Point miter_point = (start_normal + end_normal) / 2 / alignment; - if (miter_point.GetDistanceSquared({0, 0}) > - miter_limit * miter_limit) { - return; // Convert to bevel when we exceed the miter limit. - } - - // Outer miter point. - SolidStrokeVertexShader::PerVertexData vtx; - vtx.vertex_position = position; - vtx.pen_down = 1.0; - vtx.vertex_normal = miter_point * dir; - vtx_builder.AppendVertex(vtx); - }; - break; - case Join::kRound: - join_proc_ = [](VertexBufferBuilder& vtx_builder, - const Point& position, const Point& start_normal, - const Point& end_normal, Scalar miter_limit, - const SmoothingApproximation& smoothing) { - // 0 for no joint (straight line), 1 for max joint (180 degrees). - Scalar alignment = 1 - (start_normal.Dot(end_normal) + 1) / 2; - if (ScalarNearlyEqual(alignment, 0)) { - return; - } - - Scalar dir = - CreateBevel(vtx_builder, position, start_normal, end_normal); - - Point middle = (start_normal + end_normal).Normalize(); - Point middle_handle = middle + Point(-middle.y, middle.x) * - PathBuilder::kArcApproximationMagic * - alignment * dir; - Point start_handle = - start_normal + Point(start_normal.y, -start_normal.x) * - PathBuilder::kArcApproximationMagic * alignment * - dir; - - auto arc_points = CubicPathComponent(start_normal, start_handle, - middle_handle, middle) - .CreatePolyline(smoothing); - - SolidStrokeVertexShader::PerVertexData vtx; - vtx.vertex_position = position; - vtx.pen_down = 1.0; - for (const auto& point : arc_points) { - vtx.vertex_normal = point * dir; - vtx_builder.AppendVertex(vtx); - vtx.vertex_normal = (-point * dir).Reflect(middle); - vtx_builder.AppendVertex(vtx); - } - }; - break; - } -} - -SolidStrokeContents::Join SolidStrokeContents::GetStrokeJoin() { - return join_; -} - -/******************************************************************************* - ******* ClipContents - ******************************************************************************/ - -ClipContents::ClipContents() = default; - -ClipContents::~ClipContents() = default; - -bool ClipContents::Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { - using VS = ClipPipeline::VertexShader; - - Command cmd; - cmd.label = "Clip"; - cmd.pipeline = renderer.GetClipPipeline(OptionsFromPass(pass)); - cmd.stencil_reference = entity.GetStencilDepth(); - cmd.BindVertices( - CreateSolidFillVertices(entity.GetPath(), pass.GetTransientsBuffer())); - - VS::FrameInfo info; - // The color really doesn't matter. - info.color = Color::SkyBlue(); - info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()); - - VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(info)); - - pass.AddCommand(std::move(cmd)); - return true; -} - -/******************************************************************************* - ******* ClipRestoreContents - ******************************************************************************/ - -ClipRestoreContents::ClipRestoreContents() = default; - -ClipRestoreContents::~ClipRestoreContents() = default; - -bool ClipRestoreContents::Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { - using VS = ClipPipeline::VertexShader; - - Command cmd; - cmd.label = "Clip Restore"; - cmd.pipeline = renderer.GetClipRestorePipeline(OptionsFromPass(pass)); - cmd.stencil_reference = entity.GetStencilDepth(); - - // Create a rect that covers the whole render target. - auto size = pass.GetRenderTargetSize(); - VertexBufferBuilder vtx_builder; - vtx_builder.AddVertices({ - {Point(0.0, 0.0)}, - {Point(size.width, 0.0)}, - {Point(size.width, size.height)}, - {Point(0.0, 0.0)}, - {Point(size.width, size.height)}, - {Point(0.0, size.height)}, - }); - cmd.BindVertices(vtx_builder.CreateVertexBuffer(pass.GetTransientsBuffer())); - - VS::FrameInfo info; - // The color really doesn't matter. - info.color = Color::SkyBlue(); - info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()); - - VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(info)); - - pass.AddCommand(std::move(cmd)); - return true; -} - -/******************************************************************************* - ******* TextContents - ******************************************************************************/ - -TextContents::TextContents() = default; - -TextContents::~TextContents() = default; - -void TextContents::SetTextFrame(TextFrame frame) { - frame_ = std::move(frame); -} - -void TextContents::SetGlyphAtlas(std::shared_ptr atlas) { - atlas_ = std::move(atlas); -} - -void TextContents::SetColor(Color color) { - color_ = color; -} - -bool TextContents::Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { - if (color_.IsTransparent()) { - return true; - } - - if (!atlas_ || !atlas_->IsValid()) { - VALIDATION_LOG << "Cannot render glyphs without prepared atlas."; - return false; - } - - using VS = GlyphAtlasPipeline::VertexShader; - using FS = GlyphAtlasPipeline::FragmentShader; - - // Information shared by all glyph draw calls. - Command cmd; - cmd.label = "Glyph"; - cmd.primitive_type = PrimitiveType::kTriangle; - cmd.pipeline = renderer.GetGlyphAtlasPipeline(OptionsFromPass(pass)); - cmd.stencil_reference = entity.GetStencilDepth(); - - // Common vertex uniforms for all glyphs. - VS::FrameInfo frame_info; - frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * - entity.GetTransformation(); - frame_info.atlas_size = - Point{static_cast(atlas_->GetTexture()->GetSize().width), - static_cast(atlas_->GetTexture()->GetSize().height)}; - frame_info.text_color = ToVector(color_); - VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); - - // Common fragment uniforms for all glyphs. - FS::BindGlyphAtlasSampler( - cmd, // command - atlas_->GetTexture(), // texture - renderer.GetContext()->GetSamplerLibrary()->GetSampler({}) // sampler - ); - - // Common vertex information for all glyphs. - // Currently, glyphs are being drawn individually. This can be batched later. - // But we don't want to give each glyph unique vertex information. So all - // glyphs are given the same vertex information in the form of a unit-sized - // quad. The size of the glyph is specified in uniform data and the vertex - // shader uses this to size the glyph correctly. The interpolated vertex - // information is also used in the fragment shader to sample from the glyph - // atlas. - { - VertexBufferBuilder vertex_builder; - if (!Tessellator{FillType::kPositive}.Tessellate( - PathBuilder{} - .AddRect(Rect::MakeXYWH(0.0, 0.0, 1.0, 1.0)) - .TakePath() - .CreatePolyline(), - [&vertex_builder](Point point) { - VS::PerVertexData vtx; - vtx.unit_vertex = point; - vertex_builder.AppendVertex(std::move(vtx)); - })) { - return false; - } - auto dummy = vertex_builder.CreateVertexBuffer(pass.GetTransientsBuffer()); - auto vertex_buffer = dummy; - if (!vertex_buffer) { - return false; - } - cmd.BindVertices(std::move(vertex_buffer)); - } - - // Iterate through all the runs in the blob. - for (const auto& run : frame_.GetRuns()) { - auto font = run.GetFont(); - auto glyph_size = ISize::Ceil(font.GetMetrics().GetBoundingBox().size); - // Draw each glyph individually. This should probably be batched. - for (const auto& glyph_position : run.GetGlyphPositions()) { - FontGlyphPair font_glyph_pair{font, glyph_position.glyph}; - auto atlas_glyph_pos = atlas_->FindFontGlyphPosition(font_glyph_pair); - if (!atlas_glyph_pos.has_value()) { - VALIDATION_LOG << "Could not find glyph position in the atlas."; - return false; - } - - VS::GlyphInfo glyph_info; - glyph_info.position = glyph_position.position.Translate( - {font.GetMetrics().min_extent.x, font.GetMetrics().ascent, 0.0}); - glyph_info.glyph_size = {static_cast(glyph_size.width), - static_cast(glyph_size.height)}; - glyph_info.atlas_position = atlas_glyph_pos->origin; - glyph_info.atlas_glyph_size = {atlas_glyph_pos->size.width, - atlas_glyph_pos->size.height}; - VS::BindGlyphInfo(cmd, - pass.GetTransientsBuffer().EmplaceUniform(glyph_info)); - - if (!pass.AddCommand(cmd)) { - return false; - } - } - } - - return true; -} - -} // namespace impeller diff --git a/impeller/entity/contents.h b/impeller/entity/contents.h deleted file mode 100644 index f3803ff4d0222..0000000000000 --- a/impeller/entity/contents.h +++ /dev/null @@ -1,248 +0,0 @@ -// 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. - -#pragma once - -#include -#include -#include - -#include "flutter/fml/macros.h" -#include "impeller/entity/solid_stroke.vert.h" -#include "impeller/geometry/color.h" -#include "impeller/geometry/path_component.h" -#include "impeller/geometry/point.h" -#include "impeller/geometry/rect.h" -#include "impeller/renderer/texture.h" -#include "impeller/typographer/glyph_atlas.h" -#include "impeller/typographer/text_frame.h" - -namespace impeller { - -class ContentContext; -class Entity; -class Surface; -class RenderPass; - -class Contents { - public: - Contents(); - - virtual ~Contents(); - - virtual bool Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const = 0; - - private: - FML_DISALLOW_COPY_AND_ASSIGN(Contents); -}; - -class LinearGradientContents final : public Contents { - public: - LinearGradientContents(); - - ~LinearGradientContents() override; - - // |Contents| - bool Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const override; - - void SetEndPoints(Point start_point, Point end_point); - - void SetColors(std::vector colors); - - const std::vector& GetColors() const; - - private: - Point start_point_; - Point end_point_; - std::vector colors_; - - FML_DISALLOW_COPY_AND_ASSIGN(LinearGradientContents); -}; - -class SolidColorContents final : public Contents { - public: - SolidColorContents(); - - ~SolidColorContents() override; - - static std::unique_ptr Make(Color color); - - void SetColor(Color color); - - const Color& GetColor() const; - - // |Contents| - bool Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const override; - - private: - Color color_; - - FML_DISALLOW_COPY_AND_ASSIGN(SolidColorContents); -}; - -class TextureContents final : public Contents { - public: - TextureContents(); - - ~TextureContents() override; - - void SetTexture(std::shared_ptr texture); - - std::shared_ptr GetTexture() const; - - void SetSourceRect(const IRect& source_rect); - - void SetOpacity(Scalar opacity); - - const IRect& GetSourceRect() const; - - // |Contents| - bool Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const override; - - public: - std::shared_ptr texture_; - IRect source_rect_; - Scalar opacity_ = 1.0f; - - FML_DISALLOW_COPY_AND_ASSIGN(TextureContents); -}; - -class SolidStrokeContents final : public Contents { - public: - enum class Cap { - kButt, - kRound, - kSquare, - }; - - enum class Join { - kMiter, - kRound, - kBevel, - }; - - using CapProc = std::function& vtx_builder, - const Point& position, - const Point& normal, - const SmoothingApproximation& smoothing)>; - using JoinProc = std::function& vtx_builder, - const Point& position, - const Point& start_normal, - const Point& end_normal, - Scalar miter_limit, - const SmoothingApproximation& smoothing)>; - - SolidStrokeContents(); - - ~SolidStrokeContents() override; - - void SetColor(Color color); - - const Color& GetColor() const; - - void SetStrokeSize(Scalar size); - - Scalar GetStrokeSize() const; - - void SetStrokeMiter(Scalar miter_limit); - - Scalar GetStrokeMiter(); - - void SetStrokeCap(Cap cap); - - Cap GetStrokeCap(); - - void SetStrokeJoin(Join join); - - Join GetStrokeJoin(); - - // |Contents| - bool Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const override; - - private: - SmoothingApproximation arc_smoothing_approximation_; - - Color color_; - Scalar stroke_size_ = 0.0; - Scalar miter_limit_ = 4.0; - - Cap cap_; - CapProc cap_proc_; - - Join join_; - JoinProc join_proc_; - - FML_DISALLOW_COPY_AND_ASSIGN(SolidStrokeContents); -}; - -class ClipContents final : public Contents { - public: - ClipContents(); - - ~ClipContents(); - - // |Contents| - bool Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const override; - - private: - FML_DISALLOW_COPY_AND_ASSIGN(ClipContents); -}; - -class ClipRestoreContents final : public Contents { - public: - ClipRestoreContents(); - - ~ClipRestoreContents(); - - void SetGlyphAtlas(std::shared_ptr atlas); - - // |Contents| - bool Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const override; - - private: - FML_DISALLOW_COPY_AND_ASSIGN(ClipRestoreContents); -}; - -class TextContents final : public Contents { - public: - TextContents(); - - ~TextContents(); - - void SetTextFrame(TextFrame frame); - - void SetGlyphAtlas(std::shared_ptr atlas); - - void SetColor(Color color); - - // |Contents| - bool Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const override; - - private: - TextFrame frame_; - Color color_; - std::shared_ptr atlas_; - - FML_DISALLOW_COPY_AND_ASSIGN(TextContents); -}; - -} // namespace impeller diff --git a/impeller/entity/contents/clip_contents.cc b/impeller/entity/contents/clip_contents.cc new file mode 100644 index 0000000000000..07921a3356799 --- /dev/null +++ b/impeller/entity/contents/clip_contents.cc @@ -0,0 +1,88 @@ +// 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 "linear_gradient_contents.h" + +#include "impeller/entity/contents/clip_contents.h" +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/contents/solid_color_contents.h" +#include "impeller/entity/entity.h" +#include "impeller/renderer/render_pass.h" + +namespace impeller { + +/******************************************************************************* + ******* ClipContents + ******************************************************************************/ + +ClipContents::ClipContents() = default; + +ClipContents::~ClipContents() = default; + +bool ClipContents::Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = ClipPipeline::VertexShader; + + Command cmd; + cmd.label = "Clip"; + cmd.pipeline = renderer.GetClipPipeline(OptionsFromPass(pass)); + cmd.stencil_reference = entity.GetStencilDepth(); + cmd.BindVertices(SolidColorContents::CreateSolidFillVertices( + entity.GetPath(), pass.GetTransientsBuffer())); + + VS::FrameInfo info; + // The color really doesn't matter. + info.color = Color::SkyBlue(); + info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()); + + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(info)); + + pass.AddCommand(std::move(cmd)); + return true; +} + +/******************************************************************************* + ******* ClipRestoreContents + ******************************************************************************/ + +ClipRestoreContents::ClipRestoreContents() = default; + +ClipRestoreContents::~ClipRestoreContents() = default; + +bool ClipRestoreContents::Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = ClipPipeline::VertexShader; + + Command cmd; + cmd.label = "Clip Restore"; + cmd.pipeline = renderer.GetClipRestorePipeline(OptionsFromPass(pass)); + cmd.stencil_reference = entity.GetStencilDepth(); + + // Create a rect that covers the whole render target. + auto size = pass.GetRenderTargetSize(); + VertexBufferBuilder vtx_builder; + vtx_builder.AddVertices({ + {Point(0.0, 0.0)}, + {Point(size.width, 0.0)}, + {Point(size.width, size.height)}, + {Point(0.0, 0.0)}, + {Point(size.width, size.height)}, + {Point(0.0, size.height)}, + }); + cmd.BindVertices(vtx_builder.CreateVertexBuffer(pass.GetTransientsBuffer())); + + VS::FrameInfo info; + // The color really doesn't matter. + info.color = Color::SkyBlue(); + info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()); + + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(info)); + + pass.AddCommand(std::move(cmd)); + return true; +} + +}; // namespace impeller diff --git a/impeller/entity/contents/clip_contents.h b/impeller/entity/contents/clip_contents.h new file mode 100644 index 0000000000000..41fe7cf4a53e2 --- /dev/null +++ b/impeller/entity/contents/clip_contents.h @@ -0,0 +1,51 @@ +// 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. + +#pragma once + +#include +#include +#include + +#include "flutter/fml/macros.h" +#include "impeller/entity/contents/contents.h" +#include "typographer/glyph_atlas.h" + +namespace impeller { + +class GlyphAtlas; + +class ClipContents final : public Contents { + public: + ClipContents(); + + ~ClipContents(); + + // |Contents| + bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + private: + FML_DISALLOW_COPY_AND_ASSIGN(ClipContents); +}; + +class ClipRestoreContents final : public Contents { + public: + ClipRestoreContents(); + + ~ClipRestoreContents(); + + void SetGlyphAtlas(std::shared_ptr atlas); + + // |Contents| + bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + private: + FML_DISALLOW_COPY_AND_ASSIGN(ClipRestoreContents); +}; + +} // namespace impeller diff --git a/impeller/entity/content_context.cc b/impeller/entity/contents/content_context.cc similarity index 98% rename from impeller/entity/content_context.cc rename to impeller/entity/contents/content_context.cc index 0d4b23de76da5..0570a940b89a3 100644 --- a/impeller/entity/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "impeller/entity/content_context.h" +#include "impeller/entity/contents/content_context.h" #include diff --git a/impeller/entity/content_context.h b/impeller/entity/contents/content_context.h similarity index 72% rename from impeller/entity/content_context.h rename to impeller/entity/contents/content_context.h index a3b0ec270e70c..7217bf3344f19 100644 --- a/impeller/entity/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -19,7 +19,6 @@ #include "flutter/impeller/entity/solid_stroke.vert.h" #include "flutter/impeller/entity/texture_fill.frag.h" #include "flutter/impeller/entity/texture_fill.vert.h" -#include "impeller/renderer/pipeline.h" namespace impeller { @@ -37,55 +36,62 @@ using GlyphAtlasPipeline = // to redirect writing to the stencil instead of color attachments. using ClipPipeline = PipelineT; -class ContentContext { - public: - struct Options { - SampleCount sample_count = SampleCount::kCount1; - - struct Hash { - constexpr std::size_t operator()(const Options& o) const { - return fml::HashCombine(o.sample_count); - } - }; - - struct Equal { - constexpr bool operator()(const Options& lhs, const Options& rhs) const { - return lhs.sample_count == rhs.sample_count; - } - }; +struct ContentContextOptions { + SampleCount sample_count = SampleCount::kCount1; + + struct Hash { + constexpr std::size_t operator()(const ContentContextOptions& o) const { + return fml::HashCombine(o.sample_count); + } + }; + + struct Equal { + constexpr bool operator()(const ContentContextOptions& lhs, + const ContentContextOptions& rhs) const { + return lhs.sample_count == rhs.sample_count; + } }; +}; +class ContentContext { + public: ContentContext(std::shared_ptr context); ~ContentContext(); bool IsValid() const; - std::shared_ptr GetGradientFillPipeline(Options opts) const { + std::shared_ptr GetGradientFillPipeline( + ContentContextOptions opts) const { return GetPipeline(gradient_fill_pipelines_, opts); } - std::shared_ptr GetSolidFillPipeline(Options opts) const { + std::shared_ptr GetSolidFillPipeline( + ContentContextOptions opts) const { return GetPipeline(solid_fill_pipelines_, opts); } - std::shared_ptr GetTexturePipeline(Options opts) const { + std::shared_ptr GetTexturePipeline( + ContentContextOptions opts) const { return GetPipeline(texture_pipelines_, opts); } - std::shared_ptr GetSolidStrokePipeline(Options opts) const { + std::shared_ptr GetSolidStrokePipeline( + ContentContextOptions opts) const { return GetPipeline(solid_stroke_pipelines_, opts); } - std::shared_ptr GetClipPipeline(Options opts) const { + std::shared_ptr GetClipPipeline(ContentContextOptions opts) const { return GetPipeline(clip_pipelines_, opts); } - std::shared_ptr GetClipRestorePipeline(Options opts) const { + std::shared_ptr GetClipRestorePipeline( + ContentContextOptions opts) const { return GetPipeline(clip_restoration_pipelines_, opts); } - std::shared_ptr GetGlyphAtlasPipeline(Options opts) const { + std::shared_ptr GetGlyphAtlasPipeline( + ContentContextOptions opts) const { return GetPipeline(glyph_atlas_pipelines_, opts); } @@ -95,8 +101,10 @@ class ContentContext { std::shared_ptr context_; template - using Variants = std:: - unordered_map, Options::Hash, Options::Equal>; + using Variants = std::unordered_map, + ContentContextOptions::Hash, + ContentContextOptions::Equal>; // These are mutable because while the prototypes are created eagerly, any // variants requested from that are lazily created and cached in the variants @@ -110,13 +118,13 @@ class ContentContext { mutable Variants glyph_atlas_pipelines_; static void ApplyOptionsToDescriptor(PipelineDescriptor& desc, - const Options& options) { + const ContentContextOptions& options) { desc.SetSampleCount(options.sample_count); } template std::shared_ptr GetPipeline(Variants& container, - Options opts) const { + ContentContextOptions opts) const { if (!IsValid()) { return nullptr; } diff --git a/impeller/entity/contents/contents.cc b/impeller/entity/contents/contents.cc new file mode 100644 index 0000000000000..9969170852645 --- /dev/null +++ b/impeller/entity/contents/contents.cc @@ -0,0 +1,22 @@ +// 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 "impeller/entity/contents/contents.h" + +#include "impeller/entity/contents/content_context.h" +#include "impeller/renderer/render_pass.h" + +namespace impeller { + +ContentContextOptions OptionsFromPass(const RenderPass& pass) { + ContentContextOptions opts; + opts.sample_count = pass.GetRenderTarget().GetSampleCount(); + return opts; +} + +Contents::Contents() = default; + +Contents::~Contents() = default; + +} // namespace impeller diff --git a/impeller/entity/contents/contents.h b/impeller/entity/contents/contents.h new file mode 100644 index 0000000000000..8bc297736ba73 --- /dev/null +++ b/impeller/entity/contents/contents.h @@ -0,0 +1,37 @@ +// 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. + +#pragma once + +#include +#include +#include + +#include "flutter/fml/macros.h" + +namespace impeller { + +class ContentContext; +struct ContentContextOptions; +class Entity; +class Surface; +class RenderPass; + +ContentContextOptions OptionsFromPass(const RenderPass& pass); + +class Contents { + public: + Contents(); + + virtual ~Contents(); + + virtual bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const = 0; + + private: + FML_DISALLOW_COPY_AND_ASSIGN(Contents); +}; + +} // namespace impeller diff --git a/impeller/entity/contents/linear_gradient_contents.cc b/impeller/entity/contents/linear_gradient_contents.cc new file mode 100644 index 0000000000000..14ba73123be15 --- /dev/null +++ b/impeller/entity/contents/linear_gradient_contents.cc @@ -0,0 +1,79 @@ +// 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 "linear_gradient_contents.h" + +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/entity.h" +#include "impeller/renderer/render_pass.h" +#include "impeller/renderer/tessellator.h" + +namespace impeller { + +LinearGradientContents::LinearGradientContents() = default; + +LinearGradientContents::~LinearGradientContents() = default; + +void LinearGradientContents::SetEndPoints(Point start_point, Point end_point) { + start_point_ = start_point; + end_point_ = end_point; +} + +void LinearGradientContents::SetColors(std::vector colors) { + colors_ = std::move(colors); + if (colors_.empty()) { + colors_.push_back(Color::Black()); + colors_.push_back(Color::Black()); + } else if (colors_.size() < 2u) { + colors_.push_back(colors_.back()); + } +} + +const std::vector& LinearGradientContents::GetColors() const { + return colors_; +} + +bool LinearGradientContents::Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = GradientFillPipeline::VertexShader; + using FS = GradientFillPipeline::FragmentShader; + + auto vertices_builder = VertexBufferBuilder(); + { + auto result = Tessellator{entity.GetPath().GetFillType()}.Tessellate( + entity.GetPath().CreatePolyline(), [&vertices_builder](Point point) { + VS::PerVertexData vtx; + vtx.vertices = point; + vertices_builder.AppendVertex(vtx); + }); + if (!result) { + return false; + } + } + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + + FS::GradientInfo gradient_info; + gradient_info.start_point = start_point_; + gradient_info.end_point = end_point_; + gradient_info.start_color = colors_[0]; + gradient_info.end_color = colors_[1]; + + Command cmd; + cmd.label = "LinearGradientFill"; + cmd.pipeline = renderer.GetGradientFillPipeline(OptionsFromPass(pass)); + cmd.stencil_reference = entity.GetStencilDepth(); + cmd.BindVertices( + vertices_builder.CreateVertexBuffer(pass.GetTransientsBuffer())); + cmd.primitive_type = PrimitiveType::kTriangle; + FS::BindGradientInfo( + cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + return pass.AddCommand(std::move(cmd)); +} + +} // namespace impeller diff --git a/impeller/entity/contents/linear_gradient_contents.h b/impeller/entity/contents/linear_gradient_contents.h new file mode 100644 index 0000000000000..0467f8fb3a603 --- /dev/null +++ b/impeller/entity/contents/linear_gradient_contents.h @@ -0,0 +1,43 @@ +// 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. + +#pragma once + +#include +#include +#include + +#include "flutter/fml/macros.h" +#include "impeller/entity/contents/contents.h" +#include "impeller/geometry/color.h" +#include "impeller/geometry/point.h" + +namespace impeller { + +class LinearGradientContents final : public Contents { + public: + LinearGradientContents(); + + ~LinearGradientContents() override; + + // |Contents| + bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + void SetEndPoints(Point start_point, Point end_point); + + void SetColors(std::vector colors); + + const std::vector& GetColors() const; + + private: + Point start_point_; + Point end_point_; + std::vector colors_; + + FML_DISALLOW_COPY_AND_ASSIGN(LinearGradientContents); +}; + +} // namespace impeller diff --git a/impeller/entity/contents/solid_color_contents.cc b/impeller/entity/contents/solid_color_contents.cc new file mode 100644 index 0000000000000..ef61a1adab88a --- /dev/null +++ b/impeller/entity/contents/solid_color_contents.cc @@ -0,0 +1,83 @@ +// 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 "solid_color_contents.h" + +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/entity.h" +#include "impeller/geometry/path.h" +#include "impeller/renderer/render_pass.h" +#include "impeller/renderer/tessellator.h" + +namespace impeller { + +SolidColorContents::SolidColorContents() = default; + +SolidColorContents::~SolidColorContents() = default; + +void SolidColorContents::SetColor(Color color) { + color_ = color; +} + +const Color& SolidColorContents::GetColor() const { + return color_; +} + +VertexBuffer SolidColorContents::CreateSolidFillVertices(const Path& path, + HostBuffer& buffer) { + using VS = SolidFillPipeline::VertexShader; + + VertexBufferBuilder vtx_builder; + + auto tesselation_result = Tessellator{path.GetFillType()}.Tessellate( + path.CreatePolyline(), [&vtx_builder](auto point) { + VS::PerVertexData vtx; + vtx.vertices = point; + vtx_builder.AppendVertex(vtx); + }); + if (!tesselation_result) { + return {}; + } + + return vtx_builder.CreateVertexBuffer(buffer); +} + +bool SolidColorContents::Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + if (color_.IsTransparent()) { + return true; + } + + using VS = SolidFillPipeline::VertexShader; + + Command cmd; + cmd.label = "SolidFill"; + cmd.pipeline = renderer.GetSolidFillPipeline(OptionsFromPass(pass)); + cmd.stencil_reference = entity.GetStencilDepth(); + cmd.BindVertices( + CreateSolidFillVertices(entity.GetPath(), pass.GetTransientsBuffer())); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + frame_info.color = color_; + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + + cmd.primitive_type = PrimitiveType::kTriangle; + + if (!pass.AddCommand(std::move(cmd))) { + return false; + } + + return true; +} + +std::unique_ptr SolidColorContents::Make(Color color) { + auto contents = std::make_unique(); + contents->SetColor(color); + return contents; +} + +} // namespace impeller diff --git a/impeller/entity/contents/solid_color_contents.h b/impeller/entity/contents/solid_color_contents.h new file mode 100644 index 0000000000000..8f2551ca2b3d5 --- /dev/null +++ b/impeller/entity/contents/solid_color_contents.h @@ -0,0 +1,47 @@ +// 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. + +#pragma once + +#include +#include +#include + +#include "flutter/fml/macros.h" +#include "impeller/entity/contents/contents.h" +#include "impeller/geometry/color.h" + +namespace impeller { + +class Path; +class HostBuffer; +struct VertexBuffer; + +class SolidColorContents final : public Contents { + public: + SolidColorContents(); + + ~SolidColorContents() override; + + static std::unique_ptr Make(Color color); + + static VertexBuffer CreateSolidFillVertices(const Path& path, + HostBuffer& buffer); + + void SetColor(Color color); + + const Color& GetColor() const; + + // |Contents| + bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + private: + Color color_; + + FML_DISALLOW_COPY_AND_ASSIGN(SolidColorContents); +}; + +} // namespace impeller diff --git a/impeller/entity/contents/solid_stroke_contents.cc b/impeller/entity/contents/solid_stroke_contents.cc new file mode 100644 index 0000000000000..35f5cd2ba0cbb --- /dev/null +++ b/impeller/entity/contents/solid_stroke_contents.cc @@ -0,0 +1,358 @@ +// 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 "solid_stroke_contents.h" + +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/entity.h" +#include "impeller/geometry/path_builder.h" +#include "impeller/renderer/render_pass.h" + +namespace impeller { + +SolidStrokeContents::SolidStrokeContents() { + SetStrokeCap(Cap::kButt); + SetStrokeJoin(Join::kMiter); +} + +SolidStrokeContents::~SolidStrokeContents() = default; + +void SolidStrokeContents::SetColor(Color color) { + color_ = color; +} + +const Color& SolidStrokeContents::GetColor() const { + return color_; +} + +static VertexBuffer CreateSolidStrokeVertices( + const Path& path, + HostBuffer& buffer, + const SolidStrokeContents::CapProc& cap_proc, + const SolidStrokeContents::JoinProc& join_proc, + Scalar miter_limit, + const SmoothingApproximation& smoothing) { + using VS = SolidStrokeVertexShader; + + VertexBufferBuilder vtx_builder; + auto polyline = path.CreatePolyline(); + + if (polyline.points.size() < 2) { + return {}; // Nothing to render. + } + + VS::PerVertexData vtx; + + // Normal state. + Point normal; + Point previous_normal; // Used for computing joins. + + auto compute_normal = [&polyline, &normal, &previous_normal](size_t point_i) { + previous_normal = normal; + Point direction = + (polyline.points[point_i] - polyline.points[point_i - 1]).Normalize(); + normal = {-direction.y, direction.x}; + }; + + for (size_t contour_i = 0; contour_i < polyline.contours.size(); + contour_i++) { + size_t contour_start_point_i, contour_end_point_i; + std::tie(contour_start_point_i, contour_end_point_i) = + polyline.GetContourPointBounds(contour_i); + + if (contour_end_point_i - contour_start_point_i < 2) { + continue; // This contour has no renderable content. + } + + // The first point's normal is always the same as + compute_normal(contour_start_point_i + 1); + const Point contour_first_normal = normal; + + if (contour_i > 0) { + // This branch only executes when we've just finished drawing a contour + // and are switching to a new one. + // We're drawing a triangle strip, so we need to "pick up the pen" by + // appending transparent vertices between the end of the previous contour + // and the beginning of the new contour. + vtx.vertex_position = polyline.points[contour_start_point_i - 1]; + vtx.vertex_normal = {}; + vtx.pen_down = 0.0; + vtx_builder.AppendVertex(vtx); + vtx.vertex_position = polyline.points[contour_start_point_i]; + vtx_builder.AppendVertex(vtx); + } + + // Generate start cap. + if (!polyline.contours[contour_i].is_closed) { + cap_proc(vtx_builder, polyline.points[contour_start_point_i], -normal, + smoothing); + } + + // Generate contour geometry. + for (size_t point_i = contour_start_point_i; point_i < contour_end_point_i; + point_i++) { + if (point_i > contour_start_point_i) { + // Generate line rect. + vtx.vertex_position = polyline.points[point_i - 1]; + vtx.pen_down = 1.0; + vtx.vertex_normal = normal; + vtx_builder.AppendVertex(vtx); + vtx.vertex_normal = -normal; + vtx_builder.AppendVertex(vtx); + vtx.vertex_position = polyline.points[point_i]; + vtx.vertex_normal = normal; + vtx_builder.AppendVertex(vtx); + vtx.vertex_normal = -normal; + vtx_builder.AppendVertex(vtx); + + if (point_i < contour_end_point_i - 1) { + compute_normal(point_i + 1); + + // Generate join from the current line to the next line. + join_proc(vtx_builder, polyline.points[point_i], previous_normal, + normal, miter_limit, smoothing); + } + } + } + + // Generate end cap or join. + if (!polyline.contours[contour_i].is_closed) { + cap_proc(vtx_builder, polyline.points[contour_end_point_i - 1], normal, + smoothing); + } else { + join_proc(vtx_builder, polyline.points[contour_start_point_i], normal, + contour_first_normal, miter_limit, smoothing); + } + } + + return vtx_builder.CreateVertexBuffer(buffer); +} + +bool SolidStrokeContents::Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + if (color_.IsTransparent() || stroke_size_ <= 0.0) { + return true; + } + + using VS = SolidStrokeVertexShader; + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + + VS::StrokeInfo stroke_info; + stroke_info.color = color_; + stroke_info.size = stroke_size_; + + Command cmd; + cmd.primitive_type = PrimitiveType::kTriangleStrip; + cmd.label = "SolidStroke"; + cmd.pipeline = renderer.GetSolidStrokePipeline(OptionsFromPass(pass)); + cmd.stencil_reference = entity.GetStencilDepth(); + cmd.BindVertices(CreateSolidStrokeVertices( + entity.GetPath(), pass.GetTransientsBuffer(), cap_proc_, join_proc_, + miter_limit_, arc_smoothing_approximation_)); + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + VS::BindStrokeInfo(cmd, + pass.GetTransientsBuffer().EmplaceUniform(stroke_info)); + + pass.AddCommand(std::move(cmd)); + + return true; +} + +void SolidStrokeContents::SetStrokeSize(Scalar size) { + stroke_size_ = size; + arc_smoothing_approximation_ = SmoothingApproximation(5.0 / size, 0.0, 0.0); +} + +Scalar SolidStrokeContents::GetStrokeSize() const { + return stroke_size_; +} + +void SolidStrokeContents::SetStrokeMiter(Scalar miter_limit) { + if (miter_limit < 0) { + return; // Skia behaves like this. + } + miter_limit_ = miter_limit; +} + +Scalar SolidStrokeContents::GetStrokeMiter() { + return miter_limit_; +} + +void SolidStrokeContents::SetStrokeCap(Cap cap) { + cap_ = cap; + + using VS = SolidStrokeVertexShader; + switch (cap) { + case Cap::kButt: + cap_proc_ = [](VertexBufferBuilder& vtx_builder, + const Point& position, const Point& normal, + const SmoothingApproximation& smoothing) {}; + break; + case Cap::kRound: + cap_proc_ = [](VertexBufferBuilder& vtx_builder, + const Point& position, const Point& normal, + const SmoothingApproximation& smoothing) { + SolidStrokeVertexShader::PerVertexData vtx; + vtx.vertex_position = position; + vtx.pen_down = 1.0; + + Point forward(normal.y, -normal.x); + + auto arc_points = + CubicPathComponent( + normal, normal + forward * PathBuilder::kArcApproximationMagic, + forward + normal * PathBuilder::kArcApproximationMagic, forward) + .CreatePolyline(smoothing); + + vtx.vertex_normal = normal; + vtx_builder.AppendVertex(vtx); + vtx.vertex_normal = -normal; + vtx_builder.AppendVertex(vtx); + for (const auto& point : arc_points) { + vtx.vertex_normal = point; + vtx_builder.AppendVertex(vtx); + vtx.vertex_normal = (-point).Reflect(forward); + vtx_builder.AppendVertex(vtx); + } + }; + break; + case Cap::kSquare: + cap_proc_ = [](VertexBufferBuilder& vtx_builder, + const Point& position, const Point& normal, + const SmoothingApproximation& smoothing) { + SolidStrokeVertexShader::PerVertexData vtx; + vtx.vertex_position = position; + vtx.pen_down = 1.0; + + Point forward(normal.y, -normal.x); + + vtx.vertex_normal = normal; + vtx_builder.AppendVertex(vtx); + vtx.vertex_normal = -normal; + vtx_builder.AppendVertex(vtx); + vtx.vertex_normal = normal + forward; + vtx_builder.AppendVertex(vtx); + vtx.vertex_normal = -normal + forward; + vtx_builder.AppendVertex(vtx); + }; + break; + } +} + +SolidStrokeContents::Cap SolidStrokeContents::GetStrokeCap() { + return cap_; +} + +static Scalar CreateBevelAndGetDirection( + VertexBufferBuilder& vtx_builder, + const Point& position, + const Point& start_normal, + const Point& end_normal) { + SolidStrokeVertexShader::PerVertexData vtx; + vtx.vertex_position = position; + vtx.pen_down = 1.0; + vtx.vertex_normal = {}; + vtx_builder.AppendVertex(vtx); + + Scalar dir = start_normal.Cross(end_normal) > 0 ? -1 : 1; + vtx.vertex_normal = start_normal * dir; + vtx_builder.AppendVertex(vtx); + vtx.vertex_normal = end_normal * dir; + vtx_builder.AppendVertex(vtx); + + return dir; +} + +void SolidStrokeContents::SetStrokeJoin(Join join) { + join_ = join; + + using VS = SolidStrokeVertexShader; + switch (join) { + case Join::kBevel: + join_proc_ = [](VertexBufferBuilder& vtx_builder, + const Point& position, const Point& start_normal, + const Point& end_normal, Scalar miter_limit, + const SmoothingApproximation& smoothing) { + CreateBevelAndGetDirection(vtx_builder, position, start_normal, + end_normal); + }; + break; + case Join::kMiter: + join_proc_ = [](VertexBufferBuilder& vtx_builder, + const Point& position, const Point& start_normal, + const Point& end_normal, Scalar miter_limit, + const SmoothingApproximation& smoothing) { + // 1 for no joint (straight line), 0 for max joint (180 degrees). + Scalar alignment = (start_normal.Dot(end_normal) + 1) / 2; + if (ScalarNearlyEqual(alignment, 1)) { + return; + } + + Scalar dir = CreateBevelAndGetDirection(vtx_builder, position, + start_normal, end_normal); + + Point miter_point = (start_normal + end_normal) / 2 / alignment; + if (miter_point.GetDistanceSquared({0, 0}) > + miter_limit * miter_limit) { + return; // Convert to bevel when we exceed the miter limit. + } + + // Outer miter point. + SolidStrokeVertexShader::PerVertexData vtx; + vtx.vertex_position = position; + vtx.pen_down = 1.0; + vtx.vertex_normal = miter_point * dir; + vtx_builder.AppendVertex(vtx); + }; + break; + case Join::kRound: + join_proc_ = [](VertexBufferBuilder& vtx_builder, + const Point& position, const Point& start_normal, + const Point& end_normal, Scalar miter_limit, + const SmoothingApproximation& smoothing) { + // 0 for no joint (straight line), 1 for max joint (180 degrees). + Scalar alignment = 1 - (start_normal.Dot(end_normal) + 1) / 2; + if (ScalarNearlyEqual(alignment, 0)) { + return; + } + + Scalar dir = CreateBevelAndGetDirection(vtx_builder, position, + start_normal, end_normal); + + Point middle = (start_normal + end_normal).Normalize(); + Point middle_handle = middle + Point(-middle.y, middle.x) * + PathBuilder::kArcApproximationMagic * + alignment * dir; + Point start_handle = + start_normal + Point(start_normal.y, -start_normal.x) * + PathBuilder::kArcApproximationMagic * alignment * + dir; + + auto arc_points = CubicPathComponent(start_normal, start_handle, + middle_handle, middle) + .CreatePolyline(smoothing); + + SolidStrokeVertexShader::PerVertexData vtx; + vtx.vertex_position = position; + vtx.pen_down = 1.0; + for (const auto& point : arc_points) { + vtx.vertex_normal = point * dir; + vtx_builder.AppendVertex(vtx); + vtx.vertex_normal = (-point * dir).Reflect(middle); + vtx_builder.AppendVertex(vtx); + } + }; + break; + } +} + +SolidStrokeContents::Join SolidStrokeContents::GetStrokeJoin() { + return join_; +} + +} // namespace impeller diff --git a/impeller/entity/contents/solid_stroke_contents.h b/impeller/entity/contents/solid_stroke_contents.h new file mode 100644 index 0000000000000..8bb1501e0434e --- /dev/null +++ b/impeller/entity/contents/solid_stroke_contents.h @@ -0,0 +1,92 @@ +// 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. + +#pragma once + +#include +#include +#include + +#include "flutter/fml/macros.h" +#include "impeller/entity/contents/contents.h" +#include "impeller/entity/solid_stroke.vert.h" +#include "impeller/geometry/color.h" +#include "impeller/geometry/path_component.h" +#include "impeller/geometry/point.h" + +namespace impeller { + +class SolidStrokeContents final : public Contents { + public: + enum class Cap { + kButt, + kRound, + kSquare, + }; + + enum class Join { + kMiter, + kRound, + kBevel, + }; + + using CapProc = std::function& vtx_builder, + const Point& position, + const Point& normal, + const SmoothingApproximation& smoothing)>; + using JoinProc = std::function& vtx_builder, + const Point& position, + const Point& start_normal, + const Point& end_normal, + Scalar miter_limit, + const SmoothingApproximation& smoothing)>; + + SolidStrokeContents(); + + ~SolidStrokeContents() override; + + void SetColor(Color color); + + const Color& GetColor() const; + + void SetStrokeSize(Scalar size); + + Scalar GetStrokeSize() const; + + void SetStrokeMiter(Scalar miter_limit); + + Scalar GetStrokeMiter(); + + void SetStrokeCap(Cap cap); + + Cap GetStrokeCap(); + + void SetStrokeJoin(Join join); + + Join GetStrokeJoin(); + + // |Contents| + bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + private: + SmoothingApproximation arc_smoothing_approximation_; + + Color color_; + Scalar stroke_size_ = 0.0; + Scalar miter_limit_ = 4.0; + + Cap cap_; + CapProc cap_proc_; + + Join join_; + JoinProc join_proc_; + + FML_DISALLOW_COPY_AND_ASSIGN(SolidStrokeContents); +}; + +} // namespace impeller diff --git a/impeller/entity/contents/text_contents.cc b/impeller/entity/contents/text_contents.cc new file mode 100644 index 0000000000000..8e8d7fa5c768a --- /dev/null +++ b/impeller/entity/contents/text_contents.cc @@ -0,0 +1,134 @@ +// 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 "text_contents.h" + +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/entity.h" +#include "impeller/geometry/path_builder.h" +#include "impeller/renderer/render_pass.h" +#include "impeller/renderer/sampler_library.h" +#include "impeller/renderer/tessellator.h" +#include "impeller/typographer/glyph_atlas.h" + +namespace impeller { +TextContents::TextContents() = default; + +TextContents::~TextContents() = default; + +void TextContents::SetTextFrame(TextFrame frame) { + frame_ = std::move(frame); +} + +void TextContents::SetGlyphAtlas(std::shared_ptr atlas) { + atlas_ = std::move(atlas); +} + +void TextContents::SetColor(Color color) { + color_ = color; +} + +bool TextContents::Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + if (color_.IsTransparent()) { + return true; + } + + if (!atlas_ || !atlas_->IsValid()) { + VALIDATION_LOG << "Cannot render glyphs without prepared atlas."; + return false; + } + + using VS = GlyphAtlasPipeline::VertexShader; + using FS = GlyphAtlasPipeline::FragmentShader; + + // Information shared by all glyph draw calls. + Command cmd; + cmd.label = "Glyph"; + cmd.primitive_type = PrimitiveType::kTriangle; + cmd.pipeline = renderer.GetGlyphAtlasPipeline(OptionsFromPass(pass)); + cmd.stencil_reference = entity.GetStencilDepth(); + + // Common vertex uniforms for all glyphs. + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + frame_info.atlas_size = + Point{static_cast(atlas_->GetTexture()->GetSize().width), + static_cast(atlas_->GetTexture()->GetSize().height)}; + frame_info.text_color = ToVector(color_); + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + + // Common fragment uniforms for all glyphs. + FS::BindGlyphAtlasSampler( + cmd, // command + atlas_->GetTexture(), // texture + renderer.GetContext()->GetSamplerLibrary()->GetSampler({}) // sampler + ); + + // Common vertex information for all glyphs. + // Currently, glyphs are being drawn individually. This can be batched later. + // But we don't want to give each glyph unique vertex information. So all + // glyphs are given the same vertex information in the form of a unit-sized + // quad. The size of the glyph is specified in uniform data and the vertex + // shader uses this to size the glyph correctly. The interpolated vertex + // information is also used in the fragment shader to sample from the glyph + // atlas. + { + VertexBufferBuilder vertex_builder; + if (!Tessellator{FillType::kPositive}.Tessellate( + PathBuilder{} + .AddRect(Rect::MakeXYWH(0.0, 0.0, 1.0, 1.0)) + .TakePath() + .CreatePolyline(), + [&vertex_builder](Point point) { + VS::PerVertexData vtx; + vtx.unit_vertex = point; + vertex_builder.AppendVertex(std::move(vtx)); + })) { + return false; + } + auto dummy = vertex_builder.CreateVertexBuffer(pass.GetTransientsBuffer()); + auto vertex_buffer = dummy; + if (!vertex_buffer) { + return false; + } + cmd.BindVertices(std::move(vertex_buffer)); + } + + // Iterate through all the runs in the blob. + for (const auto& run : frame_.GetRuns()) { + auto font = run.GetFont(); + auto glyph_size = ISize::Ceil(font.GetMetrics().GetBoundingBox().size); + // Draw each glyph individually. This should probably be batched. + for (const auto& glyph_position : run.GetGlyphPositions()) { + FontGlyphPair font_glyph_pair{font, glyph_position.glyph}; + auto atlas_glyph_pos = atlas_->FindFontGlyphPosition(font_glyph_pair); + if (!atlas_glyph_pos.has_value()) { + VALIDATION_LOG << "Could not find glyph position in the atlas."; + return false; + } + + VS::GlyphInfo glyph_info; + glyph_info.position = glyph_position.position.Translate( + {font.GetMetrics().min_extent.x, font.GetMetrics().ascent, 0.0}); + glyph_info.glyph_size = {static_cast(glyph_size.width), + static_cast(glyph_size.height)}; + glyph_info.atlas_position = atlas_glyph_pos->origin; + glyph_info.atlas_glyph_size = {atlas_glyph_pos->size.width, + atlas_glyph_pos->size.height}; + VS::BindGlyphInfo(cmd, + pass.GetTransientsBuffer().EmplaceUniform(glyph_info)); + + if (!pass.AddCommand(cmd)) { + return false; + } + } + } + + return true; +} + +} // namespace impeller diff --git a/impeller/entity/contents/text_contents.h b/impeller/entity/contents/text_contents.h new file mode 100644 index 0000000000000..370bdd1973d2e --- /dev/null +++ b/impeller/entity/contents/text_contents.h @@ -0,0 +1,45 @@ +// 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. + +#pragma once + +#include +#include +#include + +#include "flutter/fml/macros.h" +#include "impeller/entity/contents/contents.h" +#include "impeller/geometry/color.h" +#include "impeller/typographer/text_frame.h" + +namespace impeller { + +class GlyphAtlas; + +class TextContents final : public Contents { + public: + TextContents(); + + ~TextContents(); + + void SetTextFrame(TextFrame frame); + + void SetGlyphAtlas(std::shared_ptr atlas); + + void SetColor(Color color); + + // |Contents| + bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + private: + TextFrame frame_; + Color color_; + std::shared_ptr atlas_; + + FML_DISALLOW_COPY_AND_ASSIGN(TextContents); +}; + +} // namespace impeller diff --git a/impeller/entity/contents/texture_contents.cc b/impeller/entity/contents/texture_contents.cc new file mode 100644 index 0000000000000..9717df6bfca6d --- /dev/null +++ b/impeller/entity/contents/texture_contents.cc @@ -0,0 +1,115 @@ +// 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 "texture_contents.h" + +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/entity.h" +#include "impeller/entity/texture_fill.frag.h" +#include "impeller/entity/texture_fill.vert.h" +#include "impeller/renderer/render_pass.h" +#include "impeller/renderer/sampler_library.h" +#include "impeller/renderer/tessellator.h" + +namespace impeller { + +TextureContents::TextureContents() = default; + +TextureContents::~TextureContents() = default; + +void TextureContents::SetTexture(std::shared_ptr texture) { + texture_ = std::move(texture); +} + +std::shared_ptr TextureContents::GetTexture() const { + return texture_; +} + +void TextureContents::SetOpacity(Scalar opacity) { + opacity_ = opacity; +} + +bool TextureContents::Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + if (texture_ == nullptr) { + return true; + } + + using VS = TextureFillVertexShader; + using FS = TextureFillFragmentShader; + + const auto coverage_rect = entity.GetPath().GetBoundingBox(); + + if (!coverage_rect.has_value()) { + return true; + } + + if (coverage_rect->size.IsEmpty()) { + return true; + } + + const auto texture_size = texture_->GetSize(); + if (texture_size.IsEmpty()) { + return true; + } + + if (source_rect_.IsEmpty()) { + return true; + } + + VertexBufferBuilder vertex_builder; + { + const auto tess_result = + Tessellator{entity.GetPath().GetFillType()}.Tessellate( + entity.GetPath().CreatePolyline(), + [this, &vertex_builder, &coverage_rect, &texture_size](Point vtx) { + VS::PerVertexData data; + data.vertices = vtx; + auto coverage_coords = + (vtx - coverage_rect->origin) / coverage_rect->size; + data.texture_coords = + (source_rect_.origin + source_rect_.size * coverage_coords) / + texture_size; + vertex_builder.AppendVertex(data); + }); + if (!tess_result) { + return false; + } + } + + if (!vertex_builder.HasVertices()) { + return true; + } + + auto& host_buffer = pass.GetTransientsBuffer(); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + frame_info.alpha = opacity_; + + Command cmd; + cmd.label = "TextureFill"; + cmd.pipeline = renderer.GetTexturePipeline(OptionsFromPass(pass)); + cmd.stencil_reference = entity.GetStencilDepth(); + cmd.BindVertices(vertex_builder.CreateVertexBuffer(host_buffer)); + VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); + FS::BindTextureSampler( + cmd, texture_, + renderer.GetContext()->GetSamplerLibrary()->GetSampler({})); + pass.AddCommand(std::move(cmd)); + + return true; +} + +void TextureContents::SetSourceRect(const IRect& source_rect) { + source_rect_ = source_rect; +} + +const IRect& TextureContents::GetSourceRect() const { + return source_rect_; +} + +} // namespace impeller diff --git a/impeller/entity/contents/texture_contents.h b/impeller/entity/contents/texture_contents.h new file mode 100644 index 0000000000000..fd3ff9c13200b --- /dev/null +++ b/impeller/entity/contents/texture_contents.h @@ -0,0 +1,48 @@ +// 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. + +#pragma once + +#include +#include +#include + +#include "flutter/fml/macros.h" +#include "impeller/entity/contents/contents.h" +#include "impeller/geometry/rect.h" + +namespace impeller { + +class Texture; + +class TextureContents final : public Contents { + public: + TextureContents(); + + ~TextureContents() override; + + void SetTexture(std::shared_ptr texture); + + std::shared_ptr GetTexture() const; + + void SetSourceRect(const IRect& source_rect); + + void SetOpacity(Scalar opacity); + + const IRect& GetSourceRect() const; + + // |Contents| + bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + public: + std::shared_ptr texture_; + IRect source_rect_; + Scalar opacity_ = 1.0f; + + FML_DISALLOW_COPY_AND_ASSIGN(TextureContents); +}; + +} // namespace impeller diff --git a/impeller/entity/entity.cc b/impeller/entity/entity.cc index 701702b6690ec..dc976aa6874d3 100644 --- a/impeller/entity/entity.cc +++ b/impeller/entity/entity.cc @@ -4,7 +4,7 @@ #include "impeller/entity/entity.h" -#include "impeller/entity/content_context.h" +#include "impeller/entity/contents/content_context.h" #include "impeller/renderer/render_pass.h" namespace impeller { diff --git a/impeller/entity/entity.h b/impeller/entity/entity.h index 13cc918ace955..4cad573c49136 100644 --- a/impeller/entity/entity.h +++ b/impeller/entity/entity.h @@ -4,7 +4,7 @@ #pragma once -#include "impeller/entity/contents.h" +#include "impeller/entity/contents/contents.h" #include "impeller/geometry/color.h" #include "impeller/geometry/matrix.h" #include "impeller/geometry/path.h" diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 69c14c888a17b..b33f44400227c 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -5,7 +5,7 @@ #include "impeller/entity/entity_pass.h" #include "flutter/fml/trace_event.h" -#include "impeller/entity/content_context.h" +#include "impeller/entity/contents/content_context.h" #include "impeller/geometry/path_builder.h" #include "impeller/renderer/command_buffer.h" #include "impeller/renderer/render_pass.h" diff --git a/impeller/entity/entity_pass.h b/impeller/entity/entity_pass.h index cff63df7ac68a..e2305f92fcd28 100644 --- a/impeller/entity/entity_pass.h +++ b/impeller/entity/entity_pass.h @@ -9,7 +9,7 @@ #include #include "flutter/fml/macros.h" -#include "impeller/entity/contents.h" +#include "impeller/entity/contents/contents.h" #include "impeller/entity/entity.h" #include "impeller/entity/entity_pass_delegate.h" #include "impeller/renderer/render_target.h" diff --git a/impeller/entity/entity_pass_delegate.h b/impeller/entity/entity_pass_delegate.h index 1325bcd920227..19dd4f01f8fdc 100644 --- a/impeller/entity/entity_pass_delegate.h +++ b/impeller/entity/entity_pass_delegate.h @@ -7,7 +7,7 @@ #include #include "flutter/fml/macros.h" -#include "impeller/entity/contents.h" +#include "impeller/entity/contents/contents.h" #include "impeller/renderer/texture.h" namespace impeller { diff --git a/impeller/entity/entity_playground.cc b/impeller/entity/entity_playground.cc index e65451ac8659d..da4f72d7982bb 100644 --- a/impeller/entity/entity_playground.cc +++ b/impeller/entity/entity_playground.cc @@ -4,7 +4,7 @@ #include "impeller/entity/entity_playground.h" -#include "impeller/entity/content_context.h" +#include "impeller/entity/contents/content_context.h" namespace impeller { diff --git a/impeller/entity/entity_playground.h b/impeller/entity/entity_playground.h index c506b72dc5384..68b6bad83145e 100644 --- a/impeller/entity/entity_playground.h +++ b/impeller/entity/entity_playground.h @@ -5,7 +5,7 @@ #pragma once #include "flutter/fml/macros.h" -#include "impeller/entity/content_context.h" +#include "impeller/entity/contents/content_context.h" #include "impeller/entity/entity.h" #include "impeller/playground/playground.h" diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 927a32e3b8d31..f442fa6907ccc 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "entity/contents.h" #include "flutter/testing/testing.h" +#include "impeller/entity/contents/solid_color_contents.h" +#include "impeller/entity/contents/solid_stroke_contents.h" #include "impeller/entity/entity.h" #include "impeller/entity/entity_playground.h" #include "impeller/geometry/path_builder.h"