Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion impeller/aiks/aiks_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "impeller/aiks/aiks_context.h"

#include "impeller/aiks/picture.h"
#include "impeller/entity/contents/tessellation_cache.h"

namespace impeller {

Expand Down Expand Up @@ -42,7 +43,11 @@ bool AiksContext::Render(const Picture& picture, RenderTarget& render_target) {
}

if (picture.pass) {
return picture.pass->Render(*content_context_, render_target);
auto res = picture.pass->Render(*content_context_, render_target);
// FIXME(knopp): This should be called for the last surface of the frame,
// but there's currently no way to do this.
content_context_->GetTessellationCache().FinishFrame();
return res;
Comment on lines +46 to +50
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no concept of a frame, but you could probably use the concept of a particular presentation. See context_vk, this tracks increments in the swapchain. We might need to bring a similar concept out of the platform specific backend.

}

return true;
Expand Down
15 changes: 15 additions & 0 deletions impeller/aiks/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@

namespace impeller {

namespace {
const uint32_t kTagDlRRect = 'dlrr';
const uint32_t kTagDlCircle = 'dlci';
} // namespace

Canvas::Canvas() {
Initialize(std::nullopt);
}
Expand Down Expand Up @@ -242,6 +247,11 @@ void Canvas::DrawRRect(Rect rect, Scalar corner_radius, const Paint& paint) {
.SetConvexity(Convexity::kConvex)
.AddRoundedRect(rect, corner_radius)
.TakePath();
struct {
Rect rect;
Scalar corner_radius;
} identifier = {.rect = rect, .corner_radius = corner_radius};
path.SetPathIdentifier(PathIdentifier(kTagDlRRect, identifier));
if (paint.style == Paint::Style::kFill) {
Entity entity;
entity.SetTransformation(GetCurrentTransformation());
Expand All @@ -266,6 +276,11 @@ void Canvas::DrawCircle(Point center, Scalar radius, const Paint& paint) {
.AddCircle(center, radius)
.SetConvexity(Convexity::kConvex)
.TakePath();
struct {
Point center;
Scalar radius;
} identifier = {.center = center, .radius = radius};
circle_path.SetPathIdentifier(PathIdentifier(kTagDlCircle, identifier));
DrawPath(circle_path, paint);
}

Expand Down
5 changes: 1 addition & 4 deletions impeller/display_list/dl_dispatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -889,10 +889,7 @@ void DlDispatcher::drawRRect(const SkRRect& rrect) {

// |flutter::DlOpReceiver|
void DlDispatcher::drawDRRect(const SkRRect& outer, const SkRRect& inner) {
PathBuilder builder;
builder.AddPath(skia_conversions::ToPath(outer));
builder.AddPath(skia_conversions::ToPath(inner));
canvas_.DrawPath(builder.TakePath(FillType::kOdd), paint_);
canvas_.DrawPath(skia_conversions::ToPath(outer, inner), paint_);
}

// |flutter::DlOpReceiver|
Expand Down
49 changes: 44 additions & 5 deletions impeller/display_list/skia_conversions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
namespace impeller {
namespace skia_conversions {

namespace {
const uint32_t kTagSkiaPath = 'skpa';
const uint32_t kTagSkiaRRect = 'skrr';
const uint32_t kTagSkiaDRRect = 'skdr';
} // namespace

Rect ToRect(const SkRect& rect) {
return Rect::MakeLTRB(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
}
Expand Down Expand Up @@ -121,14 +127,47 @@ Path ToPath(const SkPath& path) {
}
builder.SetConvexity(path.isConvex() ? Convexity::kConvex
: Convexity::kUnknown);
return builder.TakePath(fill_type);
auto result = builder.TakePath(fill_type);
struct {
uint32_t generation_id;
FillType fill_type;
} identifier = {
.generation_id = path.getGenerationID(),
.fill_type = fill_type,
};
result.SetPathIdentifier(PathIdentifier(kTagSkiaPath, identifier));
return result;
}

Path ToPath(const SkRRect& rrect) {
return PathBuilder{}
.AddRoundedRect(ToRect(rrect.getBounds()), ToRoundingRadii(rrect))
.SetConvexity(Convexity::kConvex)
.TakePath();
auto path =
PathBuilder{}
.AddRoundedRect(ToRect(rrect.getBounds()), ToRoundingRadii(rrect))
.SetConvexity(Convexity::kConvex)
.TakePath();
struct {
SkRRect rrect;
} identifier = {
.rrect = rrect,
};
path.SetPathIdentifier(PathIdentifier(kTagSkiaRRect, identifier));
return path;
}

Path ToPath(const SkRRect& outer, const SkRRect& inner) {
PathBuilder builder;
builder.AddPath(ToPath(outer));
builder.AddPath(ToPath(inner));
auto path = builder.TakePath(FillType::kOdd);
struct {
SkRRect outer;
SkRRect inner;
} identifier = {
.outer = outer,
.inner = inner,
};
path.SetPathIdentifier(PathIdentifier(kTagSkiaDRRect, identifier));
return path;
}

Point ToPoint(const SkPoint& point) {
Expand Down
2 changes: 2 additions & 0 deletions impeller/display_list/skia_conversions.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ Path ToPath(const SkPath& path);

Path ToPath(const SkRRect& rrect);

Path ToPath(const SkRRect& outer, const SkRRect& inner);

Path PathDataFromTextBlob(const sk_sp<SkTextBlob>& blob);

std::optional<impeller::PixelFormat> ToPixelFormat(SkColorType type);
Expand Down
6 changes: 6 additions & 0 deletions impeller/entity/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ impeller_component("entity") {
"contents/gradient_generator.h",
"contents/linear_gradient_contents.cc",
"contents/linear_gradient_contents.h",
"contents/tessellation_cache.cc",
"contents/tessellation_cache.h",
"contents/radial_gradient_contents.cc",
"contents/radial_gradient_contents.h",
"contents/runtime_effect_contents.cc",
Expand Down Expand Up @@ -261,6 +263,10 @@ impeller_component("entity") {
"../typographer",
]

cflags = [
"-g",
]

deps = [ "//flutter/fml" ]
}

Expand Down
2 changes: 2 additions & 0 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "impeller/base/strings.h"
#include "impeller/core/formats.h"
#include "impeller/entity/contents/tessellation_cache.h"
#include "impeller/entity/entity.h"
#include "impeller/renderer/command_buffer.h"
#include "impeller/renderer/pipeline_library.h"
Expand Down Expand Up @@ -162,6 +163,7 @@ ContentContext::ContentContext(std::shared_ptr<Context> context)
: context_(std::move(context)),
lazy_glyph_atlas_(std::make_shared<LazyGlyphAtlas>()),
tessellator_(std::make_shared<Tessellator>()),
tessellation_cache_(std::make_unique<TessellationCache>()),
scene_context_(std::make_shared<scene::SceneContext>(context_)) {
if (!context_ || !context_->IsValid()) {
return;
Expand Down
6 changes: 6 additions & 0 deletions impeller/entity/contents/content_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ struct ContentContextOptions {
};

class Tessellator;
class TessellationCache;

class ContentContext {
public:
Expand All @@ -342,6 +343,10 @@ class ContentContext {

std::shared_ptr<Tessellator> GetTessellator() const;

TessellationCache& GetTessellationCache() const {
return *tessellation_cache_;
}

#ifdef IMPELLER_DEBUG
std::shared_ptr<Pipeline<PipelineDescriptor>> GetCheckerboardPipeline(
ContentContextOptions opts) const {
Expand Down Expand Up @@ -853,6 +858,7 @@ class ContentContext {

bool is_valid_ = false;
std::shared_ptr<Tessellator> tessellator_;
std::unique_ptr<TessellationCache> tessellation_cache_;
Comment on lines 860 to +861
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make the tessellation cache own the tessellator?

std::shared_ptr<scene::SceneContext> scene_context_;
bool wireframe_ = false;

Expand Down
70 changes: 70 additions & 0 deletions impeller/entity/contents/tessellation_cache.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// 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/tessellation_cache.h"

#define IMPELLER_ENABLE_TESSELLATION_CACHE 1

namespace impeller {

Path::Polyline TessellationCache::GetOrCreatePolyline(
const impeller::Path& path,
Scalar scale) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you take the exact scale as a cache key then animated transformations will thrash your cache each frame despite the vertices being almost unchanged.

#if IMPELLER_ENABLE_TESSELLATION_CACHE == 1
auto path_identifier = path.GetPathIdentifier();
if (!path_identifier) {
// We can't match path without a valid identifier.
return path.CreatePolyline(scale);
}
PolylineKey key{*path_identifier, scale};
auto result = polyline_cache_.Get(key);
if (result) {
return *result;
}
auto polyline = path.CreatePolyline(scale);
polyline_cache_.Set(key, polyline);
return polyline;
#else
return path.CreatePolyline(scale);
#endif
}

Tessellator::Result TessellationCache::Tessellate(
const Tessellator& tesselator,
FillType fill_type,
const Path::Polyline& polyline,
const Tessellator::BuilderCallback& callback) {
#if IMPELLER_ENABLE_TESSELLATION_CACHE == 1
auto path_identifier = polyline.original_path_identifier;
if (!path_identifier) {
return tesselator.Tessellate(fill_type, polyline, callback);
}

TessellatorKey key{*path_identifier, fill_type};
auto result = tessellator_cache_.Get(key);
if (result) {
if (callback(result->vertices.data(), result->vertices.size(),
result->indices.data(), result->indices.size())) {
return Tessellator::Result::kSuccess;
} else {
return Tessellator::Result::kInputError;
}
}

return tesselator.Tessellate(
fill_type, polyline,
[&](const float* vertices, size_t vertices_size, const uint16_t* indices,
size_t indices_size) {
TessellatorData data;
data.vertices.assign(vertices, vertices + vertices_size);
data.indices.assign(indices, indices + indices_size);
tessellator_cache_.Set(key, data);
return callback(vertices, vertices_size, indices, indices_size);
});
#else
return tesselator.Tessellate(fill_type, polyline, callback);
#endif
Comment on lines +55 to +67
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if the tessellation cache was a bit more general and could also cache data that was generated by compute. For an example, look at the draw points geometry.

For that to work, it would likely have to be able to vend device buffers instead.

On the other hand, we'll likely batch compute workloads in ways that make these buffers difficult to use. So perhaps only using the tessellation cache for the CPU bound workloads is the way forward.

}

} // namespace impeller
Loading