[Impeller] Reland: Compute UVs in vertex stage. (flutter/engine#52303)

Compute texture UVs in the vertex stage. Reland of https://github.com/flutter/engine/pull/52106 which was reverted to investigate golden failures during the x64 to arm64 mac switch.
This commit is contained in:
Jonah Williams 2024-04-23 15:11:47 -07:00 committed by GitHub
parent 4d092e34c1
commit feca43deaf
40 changed files with 419 additions and 1046 deletions

View File

@ -40397,7 +40397,6 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel.vert + ../
ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel_decal.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel_nodecal.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/geometry/points.comp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/geometry/uv.comp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas_color.frag + ../../../flutter/LICENSE
@ -40419,6 +40418,7 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/solid_fill.vert + ../../../flut
ORIGIN: ../../../flutter/impeller/entity/shaders/texture_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/texture_fill.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/texture_fill_strict_src.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/texture_uv_fill.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/tiled_texture_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/tiled_texture_fill_external.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/vertices.frag + ../../../flutter/LICENSE
@ -43279,7 +43279,6 @@ FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel.vert
FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel_decal.frag
FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel_nodecal.frag
FILE: ../../../flutter/impeller/entity/shaders/geometry/points.comp
FILE: ../../../flutter/impeller/entity/shaders/geometry/uv.comp
FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag
FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert
FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_color.frag
@ -43301,6 +43300,7 @@ FILE: ../../../flutter/impeller/entity/shaders/solid_fill.vert
FILE: ../../../flutter/impeller/entity/shaders/texture_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/texture_fill.vert
FILE: ../../../flutter/impeller/entity/shaders/texture_fill_strict_src.frag
FILE: ../../../flutter/impeller/entity/shaders/texture_uv_fill.vert
FILE: ../../../flutter/impeller/entity/shaders/tiled_texture_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/tiled_texture_fill_external.frag
FILE: ../../../flutter/impeller/entity/shaders/vertices.frag

View File

@ -901,14 +901,12 @@ static bool UseColorSourceContents(
const std::shared_ptr<VerticesGeometry>& vertices,
const Paint& paint) {
// If there are no vertex color or texture coordinates. Or if there
// are vertex coordinates then only if the contents are an image or
// a solid color.
// are vertex coordinates but its just a color.
if (vertices->HasVertexColors()) {
return false;
}
if (vertices->HasTextureCoordinates() &&
(paint.color_source.GetType() == ColorSource::Type::kImage ||
paint.color_source.GetType() == ColorSource::Type::kColor)) {
(paint.color_source.GetType() == ColorSource::Type::kColor)) {
return true;
}
return !vertices->HasTextureCoordinates();
@ -928,8 +926,7 @@ void Canvas::DrawVertices(const std::shared_ptr<VerticesGeometry>& vertices,
entity.SetTransform(GetCurrentTransform());
entity.SetBlendMode(paint.blend_mode);
// If there are no vertex color or texture coordinates. Or if there
// are vertex coordinates then only if the contents are an image.
// If there are no vertex colors.
if (UseColorSourceContents(vertices, paint)) {
entity.SetContents(CreateContentsForGeometryWithFilters(paint, vertices));
AddRenderEntityToCurrentPass(std::move(entity));
@ -945,7 +942,6 @@ void Canvas::DrawVertices(const std::shared_ptr<VerticesGeometry>& vertices,
contents->SetBlendMode(blend_mode);
contents->SetAlpha(paint.color.alpha);
contents->SetGeometry(vertices);
contents->SetEffectTransform(image_data.effect_transform);
contents->SetTexture(image_data.texture);
contents->SetTileMode(image_data.x_tile_mode, image_data.y_tile_mode);

View File

@ -39,6 +39,7 @@ impeller_shaders("entity_shaders") {
"shaders/gradients/sweep_gradient_fill.frag",
"shaders/texture_fill.frag",
"shaders/texture_fill.vert",
"shaders/texture_uv_fill.vert",
"shaders/tiled_texture_fill.frag",
"shaders/tiled_texture_fill_external.frag",
"shaders/texture_fill_strict_src.frag",
@ -81,7 +82,6 @@ impeller_shaders("modern_entity_shaders") {
"shaders/gradients/radial_gradient_ssbo_fill.frag",
"shaders/gradients/sweep_gradient_ssbo_fill.frag",
"shaders/geometry/points.comp",
"shaders/geometry/uv.comp",
]
}

View File

@ -9,7 +9,6 @@
#include <memory>
#include <vector>
#include "flutter/fml/macros.h"
#include "impeller/entity/contents/contents.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/geometry/geometry.h"

View File

@ -118,10 +118,7 @@ class ColorSourceContents : public Contents {
RenderPass& pass,
const PipelineBuilderCallback& pipeline_callback,
typename VertexShaderT::FrameInfo frame_info,
const BindFragmentCallback& bind_fragment_callback,
bool enable_uvs = false,
Rect texture_coverage = {},
const Matrix& effect_transform = {}) const {
const BindFragmentCallback& bind_fragment_callback) const {
auto options = OptionsFromPassAndEntity(pass, entity);
GeometryResult::Mode geometry_mode = GetGeometry()->GetResultMode();
@ -181,10 +178,7 @@ class ColorSourceContents : public Contents {
}
GeometryResult geometry_result =
enable_uvs
? geometry.GetPositionUVBuffer(texture_coverage, effect_transform,
renderer, entity, pass)
: geometry.GetPositionBuffer(renderer, entity, pass);
geometry.GetPositionBuffer(renderer, entity, pass);
if (geometry_result.vertex_buffer.vertex_count == 0u) {
return true;
}

View File

@ -260,8 +260,7 @@ ContentContext::ContentContext(
? std::make_shared<RenderTargetCache>(
context_->GetResourceAllocator())
: std::move(render_target_allocator)),
host_buffer_(HostBuffer::Create(context_->GetResourceAllocator())),
pending_command_buffers_(std::make_unique<PendingCommandBuffers>()) {
host_buffer_(HostBuffer::Create(context_->GetResourceAllocator())) {
if (!context_ || !context_->IsValid()) {
return;
}
@ -422,8 +421,7 @@ ContentContext::ContentContext(
rrect_blur_pipelines_.CreateDefault(*context_, options_trianglestrip);
texture_strict_src_pipelines_.CreateDefault(*context_, options);
position_uv_pipelines_.CreateDefault(*context_, options);
tiled_texture_pipelines_.CreateDefault(*context_, options);
tiled_texture_pipelines_.CreateDefault(*context_, options, {supports_decal});
kernel_decal_pipelines_.CreateDefault(*context_, options_trianglestrip);
kernel_nodecal_pipelines_.CreateDefault(*context_, options_trianglestrip);
border_mask_blur_pipelines_.CreateDefault(*context_, options_trianglestrip);
@ -445,7 +443,7 @@ ContentContext::ContentContext(
yuv_to_rgb_filter_pipelines_.CreateDefault(*context_, options_trianglestrip);
porter_duff_blend_pipelines_.CreateDefault(*context_, options_trianglestrip,
{supports_decal});
vertices_uber_shader_.CreateDefault(*context_, options);
vertices_uber_shader_.CreateDefault(*context_, options, {supports_decal});
// GLES only shader that is unsupported on macOS.
#if defined(IMPELLER_ENABLE_OPENGLES) && !defined(FML_OS_MACOSX)
if (GetContext()->GetBackendType() == Context::BackendType::kOpenGLES) {
@ -457,11 +455,6 @@ ContentContext::ContentContext(
PointsComputeShaderPipeline::MakeDefaultPipelineDescriptor(*context_);
point_field_compute_pipelines_ =
context_->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
auto uv_pipeline_desc =
UvComputeShaderPipeline::MakeDefaultPipelineDescriptor(*context_);
uv_compute_pipelines_ =
context_->GetPipelineLibrary()->GetPipeline(uv_pipeline_desc).Get();
}
is_valid_ = true;

View File

@ -57,8 +57,8 @@
#include "impeller/entity/texture_fill.frag.h"
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/entity/texture_fill_strict_src.frag.h"
#include "impeller/entity/texture_uv_fill.vert.h"
#include "impeller/entity/tiled_texture_fill.frag.h"
#include "impeller/entity/uv.comp.h"
#include "impeller/entity/vertices.frag.h"
#include "impeller/entity/yuv_to_rgb_filter.frag.h"
@ -132,10 +132,8 @@ using TexturePipeline =
using TextureStrictSrcPipeline =
RenderPipelineHandle<TextureFillVertexShader,
TextureFillStrictSrcFragmentShader>;
using PositionUVPipeline = RenderPipelineHandle<TextureFillVertexShader,
TiledTextureFillFragmentShader>;
using TiledTexturePipeline =
RenderPipelineHandle<TextureFillVertexShader,
RenderPipelineHandle<TextureUvFillVertexShader,
TiledTextureFillFragmentShader>;
using KernelDecalPipeline =
RenderPipelineHandle<KernelVertexShader, KernelDecalFragmentShader>;
@ -260,20 +258,13 @@ using VerticesUberShader =
/// Geometry Pipelines
using PointsComputeShaderPipeline = ComputePipelineBuilder<PointsComputeShader>;
using UvComputeShaderPipeline = ComputePipelineBuilder<UvComputeShader>;
#ifdef IMPELLER_ENABLE_OPENGLES
using TiledTextureExternalPipeline =
RenderPipelineHandle<TextureFillVertexShader,
RenderPipelineHandle<TextureUvFillVertexShader,
TiledTextureFillExternalFragmentShader>;
#endif // IMPELLER_ENABLE_OPENGLES
// A struct used to isolate command buffer storage from the content
// context options to preserve const-ness.
struct PendingCommandBuffers {
std::vector<std::shared_ptr<CommandBuffer>> command_buffers;
};
/// Pipeline state configuration.
///
/// Each unique combination of these options requires a different pipeline state
@ -485,11 +476,6 @@ class ContentContext {
}
#endif // IMPELLER_ENABLE_OPENGLES
std::shared_ptr<Pipeline<PipelineDescriptor>> GetPositionUVPipeline(
ContentContextOptions opts) const {
return GetPipeline(position_uv_pipelines_, opts);
}
std::shared_ptr<Pipeline<PipelineDescriptor>> GetTiledTexturePipeline(
ContentContextOptions opts) const {
return GetPipeline(tiled_texture_pipelines_, opts);
@ -739,12 +725,6 @@ class ContentContext {
return point_field_compute_pipelines_;
}
std::shared_ptr<Pipeline<ComputePipelineDescriptor>> GetUvComputePipeline()
const {
FML_DCHECK(GetDeviceCapabilities().SupportsCompute());
return uv_compute_pipelines_;
}
std::shared_ptr<Context> GetContext() const;
const Capabilities& GetDeviceCapabilities() const;
@ -944,7 +924,6 @@ class ContentContext {
mutable Variants<TiledTextureExternalPipeline>
tiled_texture_external_pipelines_;
#endif // IMPELLER_ENABLE_OPENGLES
mutable Variants<PositionUVPipeline> position_uv_pipelines_;
mutable Variants<TiledTexturePipeline> tiled_texture_pipelines_;
mutable Variants<KernelDecalPipeline> kernel_decal_pipelines_;
mutable Variants<KernelPipeline> kernel_nodecal_pipelines_;
@ -1010,8 +989,6 @@ class ContentContext {
mutable Variants<VerticesUberShader> vertices_uber_shader_;
mutable std::shared_ptr<Pipeline<ComputePipelineDescriptor>>
point_field_compute_pipelines_;
mutable std::shared_ptr<Pipeline<ComputePipelineDescriptor>>
uv_compute_pipelines_;
template <class TypedPipeline>
std::shared_ptr<Pipeline<PipelineDescriptor>> GetPipeline(
@ -1071,7 +1048,6 @@ class ContentContext {
#endif // IMPELLER_ENABLE_3D
std::shared_ptr<RenderTargetAllocator> render_target_cache_;
std::shared_ptr<HostBuffer> host_buffer_;
std::unique_ptr<PendingCommandBuffers> pending_command_buffers_;
bool wireframe_ = false;
ContentContext(const ContentContext&) = delete;

View File

@ -14,7 +14,6 @@
#include "impeller/entity/texture_fill.frag.h"
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/entity/texture_fill_strict_src.frag.h"
#include "impeller/entity/tiled_texture_fill_external.frag.h"
#include "impeller/geometry/constants.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/vertex_buffer_builder.h"
@ -114,7 +113,6 @@ bool TextureContents::Render(const ContentContext& renderer,
using VS = TextureFillVertexShader;
using FS = TextureFillFragmentShader;
using FSExternal = TiledTextureFillExternalFragmentShader;
using FSStrict = TextureFillStrictSrcFragmentShader;
if (destination_rect_.IsEmpty() || source_rect_.IsEmpty() ||
@ -122,8 +120,9 @@ bool TextureContents::Render(const ContentContext& renderer,
return true; // Nothing to render.
}
bool is_external_texture =
[[maybe_unused]] bool is_external_texture =
texture_->GetTextureDescriptor().type == TextureType::kTextureExternalOES;
FML_DCHECK(!is_external_texture);
auto source_rect = capture.AddRect("Source rect", source_rect_);
auto texture_coords =
@ -159,46 +158,14 @@ bool TextureContents::Render(const ContentContext& renderer,
}
pipeline_options.primitive_type = PrimitiveType::kTriangleStrip;
std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline;
#ifdef IMPELLER_ENABLE_OPENGLES
if (is_external_texture) {
pipeline = renderer.GetTiledTextureExternalPipeline(pipeline_options);
}
#endif // IMPELLER_ENABLE_OPENGLES
if (!pipeline) {
if (strict_source_rect_enabled_) {
pipeline = renderer.GetTextureStrictSrcPipeline(pipeline_options);
} else {
pipeline = renderer.GetTexturePipeline(pipeline_options);
}
}
pass.SetPipeline(pipeline);
pass.SetPipeline(strict_source_rect_enabled_
? renderer.GetTextureStrictSrcPipeline(pipeline_options)
: renderer.GetTexturePipeline(pipeline_options));
pass.SetVertexBuffer(vertex_builder.CreateVertexBuffer(host_buffer));
VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
if (is_external_texture) {
FSExternal::FragInfo frag_info;
frag_info.x_tile_mode =
static_cast<int>(sampler_descriptor_.width_address_mode);
frag_info.y_tile_mode =
static_cast<int>(sampler_descriptor_.height_address_mode);
frag_info.alpha = capture.AddScalar("Alpha", GetOpacity());
auto sampler_descriptor = sampler_descriptor_;
// OES_EGL_image_external states that only CLAMP_TO_EDGE is valid, so
// we emulate all other tile modes here by remapping the texture
// coordinates.
sampler_descriptor.width_address_mode = SamplerAddressMode::kClampToEdge;
sampler_descriptor.height_address_mode = SamplerAddressMode::kClampToEdge;
FSExternal::BindFragInfo(pass, host_buffer.EmplaceUniform((frag_info)));
FSExternal::BindSAMPLEREXTERNALOESTextureSampler(
pass, texture_,
renderer.GetContext()->GetSamplerLibrary()->GetSampler(
sampler_descriptor));
} else if (strict_source_rect_enabled_) {
if (strict_source_rect_enabled_) {
// For a strict source rect, shrink the texture coordinate range by half a
// texel to ensure that linear filtering does not sample anything outside
// the source rect bounds.

View File

@ -6,8 +6,6 @@
#include "fml/logging.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/texture_fill.frag.h"
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/entity/tiled_texture_fill.frag.h"
#include "impeller/entity/tiled_texture_fill_external.frag.h"
#include "impeller/renderer/render_pass.h"
@ -116,7 +114,7 @@ bool TiledTextureContents::Render(const ContentContext& renderer,
return true;
}
using VS = TextureFillVertexShader;
using VS = TextureUvFillVertexShader;
using FS = TiledTextureFillFragmentShader;
using FSExternal = TiledTextureFillExternalFragmentShader;
@ -128,11 +126,11 @@ bool TiledTextureContents::Render(const ContentContext& renderer,
bool is_external_texture =
texture_->GetTextureDescriptor().type == TextureType::kTextureExternalOES;
bool uses_emulated_tile_mode =
UsesEmulatedTileMode(renderer.GetDeviceCapabilities());
VS::FrameInfo frame_info;
frame_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale();
frame_info.uv_transform =
Rect::MakeSize(texture_size).GetNormalizingTransform() *
GetInverseEffectTransform();
PipelineBuilderMethod pipeline_method;
@ -140,14 +138,10 @@ bool TiledTextureContents::Render(const ContentContext& renderer,
if (is_external_texture) {
pipeline_method = &ContentContext::GetTiledTextureExternalPipeline;
} else {
pipeline_method = uses_emulated_tile_mode
? &ContentContext::GetTiledTexturePipeline
: &ContentContext::GetTexturePipeline;
pipeline_method = &ContentContext::GetTiledTexturePipeline;
}
#else
pipeline_method = uses_emulated_tile_mode
? &ContentContext::GetTiledTexturePipeline
: &ContentContext::GetTexturePipeline;
pipeline_method = &ContentContext::GetTiledTexturePipeline;
#endif // IMPELLER_ENABLE_OPENGLES
PipelineBuilderCallback pipeline_callback =
@ -156,15 +150,10 @@ bool TiledTextureContents::Render(const ContentContext& renderer,
};
return ColorSourceContents::DrawGeometry<VS>(
renderer, entity, pass, pipeline_callback, frame_info,
[this, &renderer, &is_external_texture,
&uses_emulated_tile_mode](RenderPass& pass) {
[this, &renderer, &is_external_texture](RenderPass& pass) {
auto& host_buffer = renderer.GetTransientsBuffer();
if (uses_emulated_tile_mode) {
pass.SetCommandLabel("TiledTextureFill");
} else {
pass.SetCommandLabel("TextureFill");
}
pass.SetCommandLabel("TextureFill");
if (is_external_texture) {
FSExternal::FragInfo frag_info;
@ -172,17 +161,12 @@ bool TiledTextureContents::Render(const ContentContext& renderer,
frag_info.y_tile_mode = static_cast<Scalar>(y_tile_mode_);
frag_info.alpha = GetOpacityFactor();
FSExternal::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
} else if (uses_emulated_tile_mode) {
} else {
FS::FragInfo frag_info;
frag_info.x_tile_mode = static_cast<Scalar>(x_tile_mode_);
frag_info.y_tile_mode = static_cast<Scalar>(y_tile_mode_);
frag_info.alpha = GetOpacityFactor();
FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
} else {
TextureFillFragmentShader::FragInfo frag_info;
frag_info.alpha = GetOpacityFactor();
TextureFillFragmentShader::BindFragInfo(
pass, host_buffer.EmplaceUniform(frag_info));
}
if (is_external_texture) {
@ -221,10 +205,7 @@ bool TiledTextureContents::Render(const ContentContext& renderer,
}
return true;
},
/*enable_uvs=*/true,
/*texture_coverage=*/Rect::MakeSize(texture_size),
/*effect_transform=*/GetInverseEffectTransform());
});
}
std::optional<Snapshot> TiledTextureContents::RenderToSnapshot(

View File

@ -152,7 +152,7 @@ bool VerticesUVContents::Render(const ContentContext& renderer,
pass.SetCommandLabel("VerticesUV");
auto& host_buffer = renderer.GetTransientsBuffer();
const std::shared_ptr<Geometry>& geometry = parent_.GetGeometry();
const std::shared_ptr<VerticesGeometry>& geometry = parent_.GetGeometry();
auto coverage = src_contents->GetCoverage(Entity{});
if (!coverage.has_value()) {
@ -333,7 +333,8 @@ bool VerticesSimpleBlendContents::Render(const ContentContext& renderer,
frag_info.dst_coeff = blend_coefficients[2];
frag_info.dst_coeff_src_alpha = blend_coefficients[3];
frag_info.dst_coeff_src_color = blend_coefficients[4];
// Only used on devices that do not natively support advanced blends.
// These values are ignored if the platform supports native decal mode.
frag_info.tmx = static_cast<int>(tile_mode_x_);
frag_info.tmy = static_cast<int>(tile_mode_y_);
@ -366,6 +367,10 @@ bool VerticesSimpleBlendContents::Render(const ContentContext& renderer,
frag_info.alpha = alpha_;
frag_info.blend_mode = static_cast<int>(blend_mode);
// These values are ignored if the platform supports native decal mode.
frag_info.tmx = static_cast<int>(tile_mode_x_);
frag_info.tmy = static_cast<int>(tile_mode_y_);
auto& host_buffer = renderer.GetTransientsBuffer();
FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));

View File

@ -2831,12 +2831,7 @@ TEST_P(EntityTest, CanComputeGeometryForEmptyPathsWithoutCrashing) {
auto position_result =
geom->GetPositionBuffer(*GetContentContext(), entity, render_pass);
auto uv_result =
geom->GetPositionUVBuffer(Rect::MakeLTRB(0, 0, 100, 100), Matrix(),
*GetContentContext(), entity, render_pass);
EXPECT_EQ(position_result.vertex_buffer.vertex_count, 0u);
EXPECT_EQ(uv_result.vertex_buffer.vertex_count, 0u);
EXPECT_EQ(geom->GetResultMode(), GeometryResult::Mode::kNormal);
}

View File

@ -44,31 +44,6 @@ GeometryResult CircleGeometry::GetPositionBuffer(const ContentContext& renderer,
return ComputePositionGeometry(renderer, generator, entity, pass);
}
// |Geometry|
GeometryResult CircleGeometry::GetPositionUVBuffer(
Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
auto& transform = entity.GetTransform();
auto uv_transform =
texture_coverage.GetNormalizingTransform() * effect_transform;
Scalar half_width = stroke_width_ < 0 ? 0.0
: LineGeometry::ComputePixelHalfWidth(
transform, stroke_width_);
std::shared_ptr<Tessellator> tessellator = renderer.GetTessellator();
// We call the StrokedCircle method which will simplify to a
// FilledCircleGenerator if the inner_radius is <= 0.
auto generator =
tessellator->StrokedCircle(transform, center_, radius_, half_width);
return ComputePositionUVGeometry(renderer, generator, uv_transform, entity,
pass);
}
GeometryVertexType CircleGeometry::GetVertexType() const {
return GeometryVertexType::kPosition;
}

View File

@ -39,13 +39,6 @@ class CircleGeometry final : public Geometry {
// |Geometry|
std::optional<Rect> GetCoverage(const Matrix& transform) const override;
// |Geometry|
GeometryResult GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;
Point center_;
Scalar radius_;
Scalar stroke_width_;

View File

@ -33,18 +33,6 @@ GeometryResult CoverGeometry::GetPositionBuffer(const ContentContext& renderer,
};
}
// |Geometry|
GeometryResult CoverGeometry::GetPositionUVBuffer(
Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
auto rect = Rect::MakeSize(pass.GetRenderTargetSize());
return ComputeUVGeometryForRect(rect, texture_coverage, effect_transform,
renderer, entity, pass);
}
GeometryVertexType CoverGeometry::GetVertexType() const {
return GeometryVertexType::kPosition;
}

View File

@ -34,13 +34,6 @@ class CoverGeometry final : public Geometry {
// |Geometry|
std::optional<Rect> GetCoverage(const Matrix& transform) const override;
// |Geometry|
GeometryResult GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;
CoverGeometry(const CoverGeometry&) = delete;
CoverGeometry& operator=(const CoverGeometry&) = delete;

View File

@ -22,20 +22,6 @@ GeometryResult EllipseGeometry::GetPositionBuffer(
entity, pass);
}
// |Geometry|
GeometryResult EllipseGeometry::GetPositionUVBuffer(
Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
return ComputePositionUVGeometry(
renderer,
renderer.GetTessellator()->FilledEllipse(entity.GetTransform(), bounds_),
texture_coverage.GetNormalizingTransform() * effect_transform, entity,
pass);
}
GeometryVertexType EllipseGeometry::GetVertexType() const {
return GeometryVertexType::kPosition;
}

View File

@ -37,13 +37,6 @@ class EllipseGeometry final : public Geometry {
// |Geometry|
std::optional<Rect> GetCoverage(const Matrix& transform) const override;
// |Geometry|
GeometryResult GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;
Rect bounds_;
EllipseGeometry(const EllipseGeometry&) = delete;

View File

@ -54,53 +54,6 @@ GeometryResult FillPathGeometry::GetPositionBuffer(
};
}
// |Geometry|
GeometryResult FillPathGeometry::GetPositionUVBuffer(
Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
using VS = TextureFillVertexShader;
const auto& bounding_box = path_.GetBoundingBox();
if (bounding_box.has_value() && bounding_box->IsEmpty()) {
return GeometryResult{
.type = PrimitiveType::kTriangle,
.vertex_buffer =
VertexBuffer{
.vertex_buffer = {},
.vertex_count = 0,
.index_type = IndexType::k16bit,
},
.transform = pass.GetOrthographicTransform() * entity.GetTransform(),
};
}
auto uv_transform =
texture_coverage.GetNormalizingTransform() * effect_transform;
auto points = renderer.GetTessellator()->TessellateConvex(
path_, entity.GetTransform().GetMaxBasisLength());
VertexBufferBuilder<VS::PerVertexData> vertex_builder;
vertex_builder.Reserve(points.size());
for (auto i = 0u; i < points.size(); i++) {
VS::PerVertexData data;
data.position = points[i];
data.texture_coords = uv_transform * points[i];
vertex_builder.AppendVertex(data);
}
return GeometryResult{
.type = PrimitiveType::kTriangleStrip,
.vertex_buffer =
vertex_builder.CreateVertexBuffer(renderer.GetTransientsBuffer()),
.transform = entity.GetShaderTransform(pass),
.mode = GetResultMode(),
};
}
GeometryResult::Mode FillPathGeometry::GetResultMode() const {
const auto& bounding_box = path_.GetBoundingBox();
if (path_.IsConvex() ||

View File

@ -35,13 +35,6 @@ class FillPathGeometry final : public Geometry {
// |Geometry|
std::optional<Rect> GetCoverage(const Matrix& transform) const override;
// |Geometry|
GeometryResult GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;
// |Geometry|
GeometryResult::Mode GetResultMode() const override;

View File

@ -7,7 +7,6 @@
#include <memory>
#include <optional>
#include "fml/status.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/geometry/circle_geometry.h"
#include "impeller/entity/geometry/cover_geometry.h"
@ -54,120 +53,6 @@ GeometryResult Geometry::ComputePositionGeometry(
};
}
GeometryResult Geometry::ComputePositionUVGeometry(
const ContentContext& renderer,
const Tessellator::VertexGenerator& generator,
const Matrix& uv_transform,
const Entity& entity,
RenderPass& pass) {
using VT = TextureFillVertexShader::PerVertexData;
size_t count = generator.GetVertexCount();
return GeometryResult{
.type = generator.GetTriangleType(),
.vertex_buffer =
{
.vertex_buffer = renderer.GetTransientsBuffer().Emplace(
count * sizeof(VT), alignof(VT),
[&generator, &uv_transform](uint8_t* buffer) {
auto vertices = reinterpret_cast<VT*>(buffer);
generator.GenerateVertices(
[&vertices, &uv_transform](const Point& p) { //
*vertices++ = {
.position = p,
.texture_coords = uv_transform * p,
};
});
FML_DCHECK(vertices == reinterpret_cast<VT*>(buffer) +
generator.GetVertexCount());
}),
.vertex_count = count,
.index_type = IndexType::kNone,
},
.transform = entity.GetShaderTransform(pass),
};
}
VertexBufferBuilder<TextureFillVertexShader::PerVertexData>
ComputeUVGeometryCPU(
VertexBufferBuilder<SolidFillVertexShader::PerVertexData>& input,
Point texture_origin,
Size texture_coverage,
Matrix effect_transform) {
VertexBufferBuilder<TextureFillVertexShader::PerVertexData> vertex_builder;
vertex_builder.Reserve(input.GetVertexCount());
input.IterateVertices(
[&vertex_builder, &texture_coverage, &effect_transform,
&texture_origin](SolidFillVertexShader::PerVertexData old_vtx) {
TextureFillVertexShader::PerVertexData data;
data.position = old_vtx.position;
data.texture_coords = effect_transform *
(old_vtx.position - texture_origin) /
texture_coverage;
vertex_builder.AppendVertex(data);
});
return vertex_builder;
}
GeometryResult ComputeUVGeometryForRect(Rect source_rect,
Rect texture_bounds,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) {
auto& host_buffer = renderer.GetTransientsBuffer();
// Calculate UV-specific transform based on texture coverage and effect.
// For example, if the texture is 100x100 and the effect transform is
// scaling by 2.0, texture_bounds.GetNormalizingTransform() will result in a
// Matrix that scales by 0.01, and then if the effect_transform is
// Matrix::MakeScale(Vector2{2, 2}), the resulting uv_transform will have x
// and y basis vectors with scale 0.02.
auto uv_transform = texture_bounds.GetNormalizingTransform() * //
effect_transform;
// Allocate space for vertex and UV data (4 vertices)
// 0: position
// 1: UV
// 2: position
// 3: UV
// etc.
Point data[8];
// Get the raw points from the rect and transform them into UV space.
auto points = source_rect.GetPoints();
for (auto i = 0u, j = 0u; i < 8; i += 2, j++) {
// Store original coordinates.
data[i] = points[j];
// Store transformed UV coordinates.
data[i + 1] = uv_transform * points[j];
}
return GeometryResult{
.type = PrimitiveType::kTriangleStrip,
.vertex_buffer =
{
.vertex_buffer = host_buffer.Emplace(
/*buffer=*/data,
/*length=*/16 * sizeof(float),
/*align=*/alignof(float)),
.vertex_count = 4,
.index_type = IndexType::kNone,
},
.transform = entity.GetShaderTransform(pass),
};
}
GeometryResult Geometry::GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
return {};
}
GeometryResult::Mode Geometry::GetResultMode() const {
return GeometryResult::Mode::kNormal;
}

View File

@ -9,7 +9,6 @@
#include "impeller/core/vertex_buffer.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/vertex_buffer_builder.h"
@ -52,34 +51,6 @@ enum GeometryVertexType {
kUV,
};
/// @brief Compute UV geometry for a VBB that contains only position geometry.
///
/// texture_origin should be set to 0, 0 for stroke and stroke based geometry,
/// like the point field.
VertexBufferBuilder<TextureFillVertexShader::PerVertexData>
ComputeUVGeometryCPU(
VertexBufferBuilder<SolidFillVertexShader::PerVertexData>& input,
Point texture_origin,
Size texture_coverage,
Matrix effect_transform);
/// @brief Computes geometry and UV coordinates for a rectangle to be rendered.
///
/// UV is the horizontal and vertical coordinates within the texture.
///
/// @param source_rect The rectangle to be rendered.
/// @param texture_bounds The local space bounding box of the geometry.
/// @param effect_transform The transform to apply to the UV coordinates.
/// @param renderer The content context to use for allocating buffers.
/// @param entity The entity to use for the transform.
/// @param pass The render pass to use for the transform.
GeometryResult ComputeUVGeometryForRect(Rect source_rect,
Rect texture_bounds,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass);
class Geometry {
public:
static std::shared_ptr<Geometry> MakeFillPath(
@ -122,12 +93,6 @@ class Geometry {
const Entity& entity,
RenderPass& pass) const = 0;
virtual GeometryResult GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const = 0;
virtual GeometryResult::Mode GetResultMode() const;
virtual GeometryVertexType GetVertexType() const = 0;
@ -156,13 +121,6 @@ class Geometry {
const Tessellator::VertexGenerator& generator,
const Entity& entity,
RenderPass& pass);
static GeometryResult ComputePositionUVGeometry(
const ContentContext& renderer,
const Tessellator::VertexGenerator& generator,
const Matrix& uv_transform,
const Entity& entity,
RenderPass& pass);
};
} // namespace impeller

View File

@ -61,21 +61,6 @@ class ImpellerEntityUnitTestAccessor {
return StrokePathGeometry::GenerateSolidStrokeVertices(
polyline, stroke_width, miter_limit, stroke_join, stroke_cap, scale);
}
static std::vector<TextureFillVertexShader::PerVertexData>
GenerateSolidStrokeVerticesUV(const Path::Polyline& polyline,
Scalar stroke_width,
Scalar miter_limit,
Join stroke_join,
Cap stroke_cap,
Scalar scale,
Point texture_origin,
Size texture_size,
const Matrix& effect_transform) {
return StrokePathGeometry::GenerateSolidStrokeVerticesUV(
polyline, stroke_width, miter_limit, stroke_join, stroke_cap, scale,
texture_origin, texture_size, effect_transform);
}
};
namespace testing {
@ -142,95 +127,6 @@ TEST(EntityGeometryTest, RoundRectGeometryCoversArea) {
EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(1, 30, 99, 70)));
}
TEST(EntityGeometryTest, StrokePathGeometryTransformOfLine) {
auto path =
PathBuilder().AddLine(Point(100, 100), Point(200, 100)).TakePath();
auto points = std::make_unique<std::vector<Point>>();
auto polyline =
path.CreatePolyline(1.0f, std::move(points),
[&points](Path::Polyline::PointBufferPtr reclaimed) {
points = std::move(reclaimed);
});
auto vertices = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
polyline, 10.0f, 10.0f, Join::kBevel, Cap::kButt, 1.0);
std::vector<SolidFillVertexShader::PerVertexData> expected = {
{.position = Point(100.0f, 105.0f)}, //
{.position = Point(100.0f, 95.0f)}, //
{.position = Point(100.0f, 105.0f)}, //
{.position = Point(100.0f, 95.0f)}, //
{.position = Point(200.0f, 105.0f)}, //
{.position = Point(200.0f, 95.0f)}, //
{.position = Point(200.0f, 105.0f)}, //
{.position = Point(200.0f, 95.0f)}, //
};
EXPECT_SOLID_VERTICES_NEAR(vertices, expected);
{
auto uv_vertices =
ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVerticesUV(
polyline, 10.0f, 10.0f, Join::kBevel, Cap::kButt, 1.0, //
Point(50.0f, 40.0f), Size(20.0f, 40.0f), Matrix());
// uvx = (x - 50) / 20
// uvy = (y - 40) / 40
auto uv = [](const Point& p) {
return Point((p.x - 50.0f) / 20.0f, //
(p.y - 40.0f) / 40.0f);
};
std::vector<TextureFillVertexShader::PerVertexData> uv_expected;
for (size_t i = 0; i < expected.size(); i++) {
auto p = expected[i].position;
uv_expected.push_back({.position = p, .texture_coords = uv(p)});
}
EXPECT_TEXTURE_VERTICES_NEAR(uv_vertices, uv_expected);
}
{
auto uv_vertices =
ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVerticesUV(
polyline, 10.0f, 10.0f, Join::kBevel, Cap::kButt, 1.0, //
Point(50.0f, 40.0f), Size(20.0f, 40.0f),
Matrix::MakeScale({8.0f, 4.0f, 1.0f}));
// uvx = ((x * 8) - 50) / 20
// uvy = ((y * 4) - 40) / 40
auto uv = [](const Point& p) {
return Point(((p.x * 8.0f) - 50.0f) / 20.0f,
((p.y * 4.0f) - 40.0f) / 40.0f);
};
std::vector<TextureFillVertexShader::PerVertexData> uv_expected;
for (size_t i = 0; i < expected.size(); i++) {
auto p = expected[i].position;
uv_expected.push_back({.position = p, .texture_coords = uv(p)});
}
EXPECT_TEXTURE_VERTICES_NEAR(uv_vertices, uv_expected);
}
{
auto uv_vertices =
ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVerticesUV(
polyline, 10.0f, 10.0f, Join::kBevel, Cap::kButt, 1.0, //
Point(50.0f, 40.0f), Size(20.0f, 40.0f),
Matrix::MakeTranslation({8.0f, 4.0f}));
// uvx = ((x + 8) - 50) / 20
// uvy = ((y + 4) - 40) / 40
auto uv = [](const Point& p) {
return Point(((p.x + 8.0f) - 50.0f) / 20.0f,
((p.y + 4.0f) - 40.0f) / 40.0f);
};
std::vector<TextureFillVertexShader::PerVertexData> uv_expected;
for (size_t i = 0; i < expected.size(); i++) {
auto p = expected[i].position;
uv_expected.push_back({.position = p, .texture_coords = uv(p)});
}
EXPECT_TEXTURE_VERTICES_NEAR(uv_vertices, uv_expected);
}
}
TEST(EntityGeometryTest, GeometryResultHasReasonableDefaults) {
GeometryResult result;
EXPECT_EQ(result.type, PrimitiveType::kTriangleStrip);

View File

@ -108,58 +108,6 @@ GeometryResult LineGeometry::GetPositionBuffer(const ContentContext& renderer,
};
}
// |Geometry|
GeometryResult LineGeometry::GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
auto& host_buffer = renderer.GetTransientsBuffer();
using VT = TextureFillVertexShader::PerVertexData;
auto& transform = entity.GetTransform();
auto radius = ComputePixelHalfWidth(transform, width_);
auto uv_transform =
texture_coverage.GetNormalizingTransform() * effect_transform;
if (cap_ == Cap::kRound) {
std::shared_ptr<Tessellator> tessellator = renderer.GetTessellator();
auto generator = tessellator->RoundCapLine(transform, p0_, p1_, radius);
return ComputePositionUVGeometry(renderer, generator, uv_transform, entity,
pass);
}
Point corners[4];
if (!ComputeCorners(corners, transform, cap_ == Cap::kSquare)) {
return kEmptyResult;
}
size_t count = 4;
BufferView vertex_buffer =
host_buffer.Emplace(count * sizeof(VT), alignof(VT),
[&uv_transform, &corners](uint8_t* buffer) {
auto vertices = reinterpret_cast<VT*>(buffer);
for (auto& corner : corners) {
*vertices++ = {
.position = corner,
.texture_coords = uv_transform * corner,
};
}
});
return GeometryResult{
.type = PrimitiveType::kTriangleStrip,
.vertex_buffer =
{
.vertex_buffer = vertex_buffer,
.vertex_count = count,
.index_type = IndexType::kNone,
},
.transform = entity.GetShaderTransform(pass),
};
}
GeometryVertexType LineGeometry::GetVertexType() const {
return GeometryVertexType::kPosition;
}

View File

@ -57,13 +57,6 @@ class LineGeometry final : public Geometry {
// |Geometry|
std::optional<Rect> GetCoverage(const Matrix& transform) const override;
// |Geometry|
GeometryResult GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;
Point p0_;
Point p1_;
Scalar width_;

View File

@ -34,33 +34,6 @@ GeometryResult PointFieldGeometry::GetPositionBuffer(
};
}
GeometryResult PointFieldGeometry::GetPositionUVBuffer(
Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
if (renderer.GetDeviceCapabilities().SupportsCompute()) {
return GetPositionBufferGPU(renderer, entity, pass, texture_coverage,
effect_transform);
}
auto vtx_builder = GetPositionBufferCPU(renderer, entity, pass);
if (!vtx_builder.has_value()) {
return {};
}
auto uv_vtx_builder =
ComputeUVGeometryCPU(vtx_builder.value(), {0, 0},
texture_coverage.GetSize(), effect_transform);
auto& host_buffer = renderer.GetTransientsBuffer();
return {
.type = PrimitiveType::kTriangleStrip,
.vertex_buffer = uv_vtx_builder.CreateVertexBuffer(host_buffer),
.transform = entity.GetShaderTransform(pass),
};
}
std::optional<VertexBufferBuilder<SolidFillVertexShader::PerVertexData>>
PointFieldGeometry::GetPositionBufferCPU(const ContentContext& renderer,
const Entity& entity,
@ -127,9 +100,7 @@ PointFieldGeometry::GetPositionBufferCPU(const ContentContext& renderer,
GeometryResult PointFieldGeometry::GetPositionBufferGPU(
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass,
std::optional<Rect> texture_coverage,
std::optional<Matrix> effect_transform) const {
RenderPass& pass) const {
FML_DCHECK(renderer.GetDeviceCapabilities().SupportsCompute());
if (radius_ < 0.0) {
return {};
@ -186,33 +157,6 @@ GeometryResult PointFieldGeometry::GetPositionBufferGPU(
output = geometry_buffer;
}
if (texture_coverage.has_value() && effect_transform.has_value()) {
BufferView geometry_uv_buffer = host_buffer.Emplace(
nullptr, total * sizeof(Vector4),
std::max(DefaultUniformAlignment(), alignof(Vector4)));
using UV = UvComputeShader;
compute_pass->AddBufferMemoryBarrier();
compute_pass->SetCommandLabel("UV Geometry");
compute_pass->SetPipeline(renderer.GetUvComputePipeline());
UV::FrameInfo frame_info;
frame_info.count = total;
frame_info.effect_transform = effect_transform.value();
frame_info.texture_origin = {0, 0};
frame_info.texture_size = Vector2(texture_coverage.value().GetSize());
UV::BindFrameInfo(*compute_pass, host_buffer.EmplaceUniform(frame_info));
UV::BindGeometryData(*compute_pass, geometry_buffer);
UV::BindGeometryUVData(*compute_pass, geometry_uv_buffer);
if (!compute_pass->Compute(ISize(total, 1)).ok()) {
return {};
}
output = geometry_uv_buffer;
}
if (!compute_pass->EncodeCommands()) {
return {};
}

View File

@ -23,25 +23,15 @@ class PointFieldGeometry final : public Geometry {
const Entity& entity,
RenderPass& pass) const override;
// |Geometry|
GeometryResult GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;
// |Geometry|
GeometryVertexType GetVertexType() const override;
// |Geometry|
std::optional<Rect> GetCoverage(const Matrix& transform) const override;
GeometryResult GetPositionBufferGPU(
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass,
std::optional<Rect> texture_coverage = std::nullopt,
std::optional<Matrix> effect_transform = std::nullopt) const;
GeometryResult GetPositionBufferGPU(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const;
std::optional<VertexBufferBuilder<SolidFillVertexShader::PerVertexData>>
GetPositionBufferCPU(const ContentContext& renderer,

View File

@ -25,16 +25,6 @@ GeometryResult RectGeometry::GetPositionBuffer(const ContentContext& renderer,
};
}
// |Geometry|
GeometryResult RectGeometry::GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
return ComputeUVGeometryForRect(rect_, texture_coverage, effect_transform,
renderer, entity, pass);
}
GeometryVertexType RectGeometry::GetVertexType() const {
return GeometryVertexType::kPosition;
}

View File

@ -32,13 +32,6 @@ class RectGeometry final : public Geometry {
// |Geometry|
std::optional<Rect> GetCoverage(const Matrix& transform) const override;
// |Geometry|
GeometryResult GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;
private:
Rect rect_;

View File

@ -19,21 +19,6 @@ GeometryResult RoundRectGeometry::GetPositionBuffer(
entity, pass);
}
// |Geometry|
GeometryResult RoundRectGeometry::GetPositionUVBuffer(
Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
return ComputePositionUVGeometry(
renderer,
renderer.GetTessellator()->FilledRoundRect(entity.GetTransform(), bounds_,
radii_),
texture_coverage.GetNormalizingTransform() * effect_transform, entity,
pass);
}
GeometryVertexType RoundRectGeometry::GetVertexType() const {
return GeometryVertexType::kPosition;
}

View File

@ -37,13 +37,6 @@ class RoundRectGeometry final : public Geometry {
// |Geometry|
std::optional<Rect> GetCoverage(const Matrix& transform) const override;
// |Geometry|
GeometryResult GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;
const Rect bounds_;
const Size radii_;

View File

@ -7,7 +7,6 @@
#include "impeller/core/buffer_view.h"
#include "impeller/core/formats.h"
#include "impeller/entity/geometry/geometry.h"
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/geometry/path_builder.h"
#include "impeller/geometry/path_component.h"
@ -45,49 +44,6 @@ class PositionWriter {
std::vector<SolidFillVertexShader::PerVertexData> data_ = {};
};
class PositionUVWriter {
public:
PositionUVWriter(const Point& texture_origin,
const Size& texture_size,
const Matrix& effect_transform)
: texture_origin_(texture_origin),
texture_size_(texture_size),
effect_transform_(effect_transform) {}
const std::vector<TextureFillVertexShader::PerVertexData>& GetData() {
if (effect_transform_.IsIdentity()) {
auto origin = texture_origin_;
auto scale = 1.0 / texture_size_;
for (auto& pvd : data_) {
pvd.texture_coords = (pvd.position - origin) * scale;
}
} else {
auto texture_rect = Rect::MakeOriginSize(texture_origin_, texture_size_);
Matrix uv_transform =
texture_rect.GetNormalizingTransform() * effect_transform_;
for (auto& pvd : data_) {
pvd.texture_coords = uv_transform * pvd.position;
}
}
return data_;
}
void AppendVertex(const Point& point) {
data_.emplace_back(TextureFillVertexShader::PerVertexData{
.position = point,
// .texture_coords = default, will be filled in during |GetData()|
});
}
private:
std::vector<TextureFillVertexShader::PerVertexData> data_ = {};
const Point texture_origin_;
const Size texture_size_;
const Matrix effect_transform_;
};
template <typename VertexWriter>
class StrokeGenerator {
public:
@ -525,27 +481,6 @@ StrokePathGeometry::GenerateSolidStrokeVertices(const Path::Polyline& polyline,
return vtx_builder.GetData();
}
std::vector<TextureFillVertexShader::PerVertexData>
StrokePathGeometry::GenerateSolidStrokeVerticesUV(
const Path::Polyline& polyline,
Scalar stroke_width,
Scalar miter_limit,
Join stroke_join,
Cap stroke_cap,
Scalar scale,
Point texture_origin,
Size texture_size,
const Matrix& effect_transform) {
auto scaled_miter_limit = stroke_width * miter_limit * 0.5f;
auto join_proc = GetJoinProc<PositionUVWriter>(stroke_join);
auto cap_proc = GetCapProc<PositionUVWriter>(stroke_cap);
StrokeGenerator stroke_generator(polyline, stroke_width, scaled_miter_limit,
join_proc, cap_proc, scale);
PositionUVWriter vtx_builder(texture_origin, texture_size, effect_transform);
stroke_generator.Generate(vtx_builder);
return vtx_builder.GetData();
}
StrokePathGeometry::StrokePathGeometry(const Path& path,
Scalar stroke_width,
Scalar miter_limit,
@ -619,52 +554,6 @@ GeometryResult StrokePathGeometry::GetPositionBuffer(
};
}
GeometryResult StrokePathGeometry::GetPositionUVBuffer(
Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
if (stroke_width_ < 0.0) {
return {};
}
auto determinant = entity.GetTransform().GetDeterminant();
if (determinant == 0) {
return {};
}
Scalar min_size = 1.0f / sqrt(std::abs(determinant));
Scalar stroke_width = std::max(stroke_width_, min_size);
auto& host_buffer = renderer.GetTransientsBuffer();
auto scale = entity.GetTransform().GetMaxBasisLength();
auto polyline = renderer.GetTessellator()->CreateTempPolyline(path_, scale);
PositionUVWriter writer(Point{0, 0}, texture_coverage.GetSize(),
effect_transform);
CreateSolidStrokeVertices(writer, polyline, stroke_width,
miter_limit_ * stroke_width_ * 0.5f,
GetJoinProc<PositionUVWriter>(stroke_join_),
GetCapProc<PositionUVWriter>(stroke_cap_), scale);
BufferView buffer_view = host_buffer.Emplace(
writer.GetData().data(),
writer.GetData().size() * sizeof(TextureFillVertexShader::PerVertexData),
alignof(TextureFillVertexShader::PerVertexData));
return GeometryResult{
.type = PrimitiveType::kTriangleStrip,
.vertex_buffer =
{
.vertex_buffer = buffer_view,
.vertex_count = writer.GetData().size(),
.index_type = IndexType::kNone,
},
.transform = entity.GetShaderTransform(pass),
.mode = GeometryResult::Mode::kPreventOverdraw,
};
}
GeometryResult::Mode StrokePathGeometry::GetResultMode() const {
return GeometryResult::Mode::kPreventOverdraw;
}

View File

@ -34,13 +34,6 @@ class StrokePathGeometry final : public Geometry {
const Entity& entity,
RenderPass& pass) const override;
// |Geometry|
GeometryResult GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;
// |Geometry|
GeometryResult::Mode GetResultMode() const override;
@ -59,17 +52,6 @@ class StrokePathGeometry final : public Geometry {
Cap stroke_cap,
Scalar scale);
static std::vector<TextureFillVertexShader::PerVertexData>
GenerateSolidStrokeVerticesUV(const Path::Polyline& polyline,
Scalar stroke_width,
Scalar miter_limit,
Join stroke_join,
Cap stroke_cap,
Scalar scale,
Point texture_origin,
Size texture_size,
const Matrix& effect_transform);
friend class ImpellerBenchmarkAccessor;
friend class ImpellerEntityUnitTestAccessor;

View File

@ -9,6 +9,7 @@
#include "impeller/core/buffer_view.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/geometry/color.h"
namespace impeller {

View File

@ -37,12 +37,11 @@ class VerticesGeometry final : public Geometry {
const Entity& entity,
RenderPass& pass) const;
// |Geometry|
GeometryResult GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;
RenderPass& pass) const;
// |Geometry|
GeometryResult GetPositionBuffer(const ContentContext& renderer,

View File

@ -3,12 +3,17 @@
// found in the LICENSE file.
#include <impeller/blending.glsl>
#include <impeller/texture.glsl>
#include <impeller/types.glsl>
#include "blend_select.glsl"
layout(constant_id = 0) const float supports_decal = 1.0;
uniform FragInfo {
float16_t alpha;
float16_t blend_mode;
float tmx;
float tmy;
}
frag_info;
@ -19,13 +24,24 @@ in mediump f16vec4 v_color;
out f16vec4 frag_color;
f16vec4 Sample(f16sampler2D texture_sampler,
vec2 texture_coords,
float tmx,
float tmy) {
if (supports_decal > 0.0) {
return texture(texture_sampler, texture_coords);
}
return IPHalfSampleWithTileMode(texture_sampler, texture_coords, tmx, tmy);
}
// A shader that implements the required src/dst blending for drawVertices and
// drawAtlas advanced blends without requiring an offscreen render pass. This is
// done in a single shader to reduce the permutations of PSO needed at runtime
// for rarely used features.
void main() {
f16vec4 dst = IPHalfUnpremultiply(v_color);
f16vec4 src = IPHalfUnpremultiply(texture(texture_sampler, v_texture_coords));
f16vec4 src = IPHalfUnpremultiply(
Sample(texture_sampler, v_texture_coords, frag_info.tmx, frag_info.tmy));
f16vec3 blend_result =
AdvancedBlend(dst.rgb, src.rgb, int(frag_info.blend_mode - 14.0));
frag_color = IPApplyBlendedColor(dst, src, blend_result);

View File

@ -1,60 +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/texture.glsl>
#include <impeller/types.glsl>
// Unused, see See PointFieldGeometry::GetPositionBuffer
layout(local_size_x = 16) in;
layout(std430) readonly buffer GeometryData {
// Size of this input data is frame_info.count;
vec2 points[];
}
geometry_data;
layout(std430) writeonly buffer GeometryUVData {
// Size of this output data is frame_info.count;
// x,y is the original geometry.
// u,v is the texture UV.
vec4 points_uv[];
}
geometry_uv_data;
uniform FrameInfo {
uint count;
mat4 effect_transform;
vec2 texture_origin;
vec2 texture_size;
}
frame_info;
vec2 project_point(mat4 m, vec2 v) {
float w = v.x * m[0][3] + v.y * m[1][3] + m[3][3];
vec2 result = vec2(v.x * m[0][0] + v.y * m[1][0] + m[3][0],
v.x * m[0][1] + v.y * m[1][1] + m[3][1]);
// This is Skia's behavior, but it may be reasonable to allow UB for the w=0
// case.
if (w != 0) {
w = 1 / w;
}
return result * w;
}
void main() {
uint ident = gl_GlobalInvocationID.x;
if (ident >= frame_info.count) {
return;
}
vec2 point = geometry_data.points[ident];
vec2 coverage_coords =
(point - frame_info.texture_origin) / frame_info.texture_size;
vec2 texture_coords =
project_point(frame_info.effect_transform, coverage_coords);
geometry_uv_data.points_uv[ident] = vec4(point, texture_coords);
}

View File

@ -0,0 +1,26 @@
// 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/conversions.glsl>
#include <impeller/types.glsl>
// A shader that computes texture UVs from a normalizing transform.
uniform FrameInfo {
mat4 mvp;
// A normlizing transform created from the texture bounds and effect transform
mat4 uv_transform;
float texture_sampler_y_coord_scale;
}
frame_info;
in vec2 position;
out vec2 v_texture_coords;
void main() {
gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0);
vec2 texture_coords = (frame_info.uv_transform * vec4(position, 0.0, 1.0)).xy;
v_texture_coords =
IPRemapCoords(texture_coords, frame_info.texture_sampler_y_coord_scale);
}

View File

@ -7,6 +7,8 @@ precision mediump float;
#include <impeller/texture.glsl>
#include <impeller/types.glsl>
layout(constant_id = 0) const float supports_decal = 1.0;
uniform f16sampler2D texture_sampler;
uniform FragInfo {
@ -21,11 +23,18 @@ in highp vec2 v_texture_coords;
out f16vec4 frag_color;
void main() {
frag_color =
IPHalfSampleWithTileMode(texture_sampler, // sampler
v_texture_coords, // texture coordinates
float16_t(frag_info.x_tile_mode), // x tile mode
float16_t(frag_info.y_tile_mode) // y tile mode
) *
float16_t(frag_info.alpha);
if (supports_decal == 1.0) {
frag_color = texture(texture_sampler, // sampler
v_texture_coords, // texture coordinates
float16_t(kDefaultMipBias)) *
float16_t(frag_info.alpha);
} else {
frag_color = IPHalfSampleWithTileMode(
texture_sampler, // sampler
v_texture_coords, // texture coordinates
float16_t(frag_info.x_tile_mode), // x tile mode
float16_t(frag_info.y_tile_mode) // y tile mode
) *
float16_t(frag_info.alpha);
}
}

View File

@ -5,7 +5,6 @@
#include "flutter/benchmarking/benchmarking.h"
#include "flutter/impeller/entity/solid_fill.vert.h"
#include "flutter/impeller/entity/texture_fill.vert.h"
#include "impeller/entity/geometry/stroke_path_geometry.h"
#include "impeller/geometry/path.h"
@ -26,21 +25,6 @@ class ImpellerBenchmarkAccessor {
return StrokePathGeometry::GenerateSolidStrokeVertices(
polyline, stroke_width, miter_limit, stroke_join, stroke_cap, scale);
}
static std::vector<TextureFillVertexShader::PerVertexData>
GenerateSolidStrokeVerticesUV(const Path::Polyline& polyline,
Scalar stroke_width,
Scalar miter_limit,
Join stroke_join,
Cap stroke_cap,
Scalar scale,
Point texture_origin,
Size texture_size,
const Matrix& effect_transform) {
return StrokePathGeometry::GenerateSolidStrokeVerticesUV(
polyline, stroke_width, miter_limit, stroke_join, stroke_cap, scale,
texture_origin, texture_size, effect_transform);
}
};
namespace {
@ -97,28 +81,16 @@ static void BM_Polyline(benchmark::State& state, Args&&... args) {
state.counters["TotalPointCount"] = point_count;
}
enum class UVMode {
kNoUV,
kUVRect,
kUVRectTx,
};
template <class... Args>
static void BM_StrokePolyline(benchmark::State& state, Args&&... args) {
auto args_tuple = std::make_tuple(std::move(args)...);
auto path = std::get<Path>(args_tuple);
auto cap = std::get<Cap>(args_tuple);
auto join = std::get<Join>(args_tuple);
auto generate_uv = std::get<UVMode>(args_tuple);
const Scalar stroke_width = 5.0f;
const Scalar miter_limit = 10.0f;
const Scalar scale = 1.0f;
const Point texture_origin = Point(0, 0);
const Size texture_size = Size(100, 100);
const Matrix effect_transform = (generate_uv == UVMode::kUVRectTx)
? Matrix::MakeScale({2.0f, 2.0f, 1.0f})
: Matrix();
auto points = std::make_unique<std::vector<Point>>();
points->reserve(2048);
@ -131,16 +103,9 @@ static void BM_StrokePolyline(benchmark::State& state, Args&&... args) {
size_t point_count = 0u;
size_t single_point_count = 0u;
while (state.KeepRunning()) {
if (generate_uv == UVMode::kNoUV) {
auto vertices = ImpellerBenchmarkAccessor::GenerateSolidStrokeVertices(
polyline, stroke_width, miter_limit, join, cap, scale);
single_point_count = vertices.size();
} else {
auto vertices = ImpellerBenchmarkAccessor::GenerateSolidStrokeVerticesUV(
polyline, stroke_width, miter_limit, join, cap, scale, //
texture_origin, texture_size, effect_transform);
single_point_count = vertices.size();
}
auto vertices = ImpellerBenchmarkAccessor::GenerateSolidStrokeVertices(
polyline, stroke_width, miter_limit, join, cap, scale);
single_point_count = vertices.size();
point_count += single_point_count;
}
state.counters["SinglePointCount"] = single_point_count;
@ -167,7 +132,7 @@ static void BM_Convex(benchmark::State& state, Args&&... args) {
#define MAKE_STROKE_BENCHMARK_CAPTURE(path, cap, join, closed, uvname, uvtype) \
BENCHMARK_CAPTURE(BM_StrokePolyline, stroke_##path##_##cap##_##join##uvname, \
Create##path(closed), Cap::k##cap, Join::k##join, uvtype)
Create##path(closed), Cap::k##cap, Join::k##join)
#define MAKE_STROKE_BENCHMARK_CAPTURE_CAPS_JOINS(path, uvname, uvtype) \
MAKE_STROKE_BENCHMARK_CAPTURE(path, Butt, Bevel, false, uvname, uvtype); \
@ -176,22 +141,12 @@ static void BM_Convex(benchmark::State& state, Args&&... args) {
MAKE_STROKE_BENCHMARK_CAPTURE(path, Square, Bevel, false, uvname, uvtype); \
MAKE_STROKE_BENCHMARK_CAPTURE(path, Round, Bevel, false, uvname, uvtype)
#define MAKE_STROKE_BENCHMARK_CAPTURE_UVS(path) \
MAKE_STROKE_BENCHMARK_CAPTURE_CAPS_JOINS(path, , UVMode::kNoUV); \
MAKE_STROKE_BENCHMARK_CAPTURE_CAPS_JOINS(path, _uv, UVMode::kUVRectTx); \
MAKE_STROKE_BENCHMARK_CAPTURE_CAPS_JOINS(path, _uvNoTx, UVMode::kUVRect)
BENCHMARK_CAPTURE(BM_Polyline, cubic_polyline, CreateCubic(true), false);
BENCHMARK_CAPTURE(BM_Polyline, cubic_polyline_tess, CreateCubic(true), true);
BENCHMARK_CAPTURE(BM_Polyline,
unclosed_cubic_polyline,
CreateCubic(false),
false);
BENCHMARK_CAPTURE(BM_Polyline,
unclosed_cubic_polyline_tess,
CreateCubic(false),
true);
MAKE_STROKE_BENCHMARK_CAPTURE_UVS(Cubic);
BENCHMARK_CAPTURE(BM_Polyline, quad_polyline, CreateQuadratic(true), false);
BENCHMARK_CAPTURE(BM_Polyline, quad_polyline_tess, CreateQuadratic(true), true);
@ -199,16 +154,9 @@ BENCHMARK_CAPTURE(BM_Polyline,
unclosed_quad_polyline,
CreateQuadratic(false),
false);
BENCHMARK_CAPTURE(BM_Polyline,
unclosed_quad_polyline_tess,
CreateQuadratic(false),
true);
MAKE_STROKE_BENCHMARK_CAPTURE_UVS(Quadratic);
BENCHMARK_CAPTURE(BM_Convex, rrect_convex, CreateRRect(), true);
MAKE_STROKE_BENCHMARK_CAPTURE(RRect, Butt, Bevel, , , UVMode::kNoUV);
MAKE_STROKE_BENCHMARK_CAPTURE(RRect, Butt, Bevel, , _uv, UVMode::kUVRectTx);
MAKE_STROKE_BENCHMARK_CAPTURE(RRect, Butt, Bevel, , _uvNoTx, UVMode::kUVRect);
MAKE_STROKE_BENCHMARK_CAPTURE(RRect, Butt, Bevel, , , );
namespace {

View File

@ -5710,12 +5710,169 @@
}
}
},
"flutter/impeller/entity/gles/texture_uv_fill.vert.gles": {
"Mali-G78": {
"core": "Mali-G78",
"filename": "flutter/impeller/entity/gles/texture_uv_fill.vert.gles",
"has_uniform_computation": true,
"type": "Vertex",
"variants": {
"Position": {
"fp16_arithmetic": 0,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
"load_store"
],
"longest_path_cycles": [
0.140625,
0.140625,
0.0,
0.0,
2.0,
0.0
],
"pipelines": [
"arith_total",
"arith_fma",
"arith_cvt",
"arith_sfu",
"load_store",
"texture"
],
"shortest_path_bound_pipelines": [
"load_store"
],
"shortest_path_cycles": [
0.140625,
0.140625,
0.0,
0.0,
2.0,
0.0
],
"total_bound_pipelines": [
"load_store"
],
"total_cycles": [
0.140625,
0.140625,
0.0,
0.0,
2.0,
0.0
]
},
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 28,
"work_registers_used": 32
},
"Varying": {
"fp16_arithmetic": 0,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
"load_store"
],
"longest_path_cycles": [
0.078125,
0.078125,
0.015625,
0.0,
3.0,
0.0
],
"pipelines": [
"arith_total",
"arith_fma",
"arith_cvt",
"arith_sfu",
"load_store",
"texture"
],
"shortest_path_bound_pipelines": [
"load_store"
],
"shortest_path_cycles": [
0.078125,
0.078125,
0.015625,
0.0,
3.0,
0.0
],
"total_bound_pipelines": [
"load_store"
],
"total_cycles": [
0.078125,
0.078125,
0.015625,
0.0,
3.0,
0.0
]
},
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 16,
"work_registers_used": 9
}
}
},
"Mali-T880": {
"core": "Mali-T880",
"filename": "flutter/impeller/entity/gles/texture_uv_fill.vert.gles",
"has_uniform_computation": false,
"type": "Vertex",
"variants": {
"Main": {
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
"load_store"
],
"longest_path_cycles": [
3.299999952316284,
4.0,
0.0
],
"pipelines": [
"arithmetic",
"load_store",
"texture"
],
"shortest_path_bound_pipelines": [
"load_store"
],
"shortest_path_cycles": [
3.299999952316284,
4.0,
0.0
],
"total_bound_pipelines": [
"load_store"
],
"total_cycles": [
3.3333332538604736,
4.0,
0.0
]
},
"thread_occupancy": 100,
"uniform_registers_used": 7,
"work_registers_used": 3
}
}
}
},
"flutter/impeller/entity/gles/tiled_texture_fill.frag.gles": {
"Mali-G78": {
"core": "Mali-G78",
"filename": "flutter/impeller/entity/gles/tiled_texture_fill.frag.gles",
"has_side_effects": false,
"has_uniform_computation": true,
"has_uniform_computation": false,
"modifies_coverage": false,
"reads_color_buffer": false,
"type": "Fragment",
@ -5723,17 +5880,17 @@
"uses_late_zs_update": false,
"variants": {
"Main": {
"fp16_arithmetic": 33,
"fp16_arithmetic": 100,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
"arith_total",
"arith_cvt"
"varying",
"texture"
],
"longest_path_cycles": [
0.265625,
0.046875,
0.03125,
0.265625,
0.046875,
0.0,
0.0,
0.25,
@ -5753,22 +5910,22 @@
"texture"
],
"shortest_path_cycles": [
0.0625,
0.03125,
0.0625,
0.03125,
0.015625,
0.0,
0.0,
0.25,
0.25
],
"total_bound_pipelines": [
"arith_total",
"arith_cvt"
"varying",
"texture"
],
"total_cycles": [
0.265625,
0.046875,
0.03125,
0.265625,
0.046875,
0.0,
0.0,
0.25,
@ -5792,10 +5949,12 @@
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
"arithmetic"
"arithmetic",
"load_store",
"texture"
],
"longest_path_cycles": [
3.299999952316284,
1.0,
1.0,
1.0
],
@ -5805,18 +5964,21 @@
"texture"
],
"shortest_path_bound_pipelines": [
"arithmetic"
"arithmetic",
"load_store",
"texture"
],
"shortest_path_cycles": [
1.3200000524520874,
1.0,
0.0
1.0,
1.0
],
"total_bound_pipelines": [
"arithmetic"
"load_store",
"texture"
],
"total_cycles": [
3.6666667461395264,
0.6666666865348816,
1.0,
1.0
]
@ -6085,7 +6247,7 @@
"longest_path_cycles": [
1.2625000476837158,
1.2625000476837158,
0.699999988079071,
0.675000011920929,
0.3125,
0.0,
0.5,
@ -6104,10 +6266,10 @@
"varying"
],
"shortest_path_cycles": [
0.390625,
0.421875,
0.421875,
0.375,
0.390625,
0.0,
0.0625,
0.0,
0.5,
0.25
@ -6119,7 +6281,7 @@
"total_cycles": [
3.862499952316284,
3.862499952316284,
2.825000047683716,
2.799999952316284,
0.9375,
0.0,
0.5,
@ -8925,6 +9087,118 @@
}
}
},
"flutter/impeller/entity/texture_uv_fill.vert.vkspv": {
"Mali-G78": {
"core": "Mali-G78",
"filename": "flutter/impeller/entity/texture_uv_fill.vert.vkspv",
"has_uniform_computation": true,
"type": "Vertex",
"variants": {
"Position": {
"fp16_arithmetic": 0,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
"load_store"
],
"longest_path_cycles": [
0.125,
0.125,
0.0,
0.0,
2.0,
0.0
],
"pipelines": [
"arith_total",
"arith_fma",
"arith_cvt",
"arith_sfu",
"load_store",
"texture"
],
"shortest_path_bound_pipelines": [
"load_store"
],
"shortest_path_cycles": [
0.125,
0.125,
0.0,
0.0,
2.0,
0.0
],
"total_bound_pipelines": [
"load_store"
],
"total_cycles": [
0.125,
0.125,
0.0,
0.0,
2.0,
0.0
]
},
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 40,
"work_registers_used": 32
},
"Varying": {
"fp16_arithmetic": 0,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
"load_store"
],
"longest_path_cycles": [
0.078125,
0.078125,
0.015625,
0.0,
3.0,
0.0
],
"pipelines": [
"arith_total",
"arith_fma",
"arith_cvt",
"arith_sfu",
"load_store",
"texture"
],
"shortest_path_bound_pipelines": [
"load_store"
],
"shortest_path_cycles": [
0.078125,
0.078125,
0.015625,
0.0,
3.0,
0.0
],
"total_bound_pipelines": [
"load_store"
],
"total_cycles": [
0.078125,
0.078125,
0.015625,
0.0,
3.0,
0.0
]
},
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 32,
"work_registers_used": 9
}
}
}
},
"flutter/impeller/entity/tiled_texture_fill.frag.vkspv": {
"Mali-G78": {
"core": "Mali-G78",
@ -8938,20 +9212,18 @@
"uses_late_zs_update": false,
"variants": {
"Main": {
"fp16_arithmetic": 33,
"fp16_arithmetic": 100,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
"arith_total",
"arith_cvt",
"varying",
"texture"
],
"longest_path_cycles": [
0.25,
0.03125,
0.25,
0.0625,
0.03125,
0.015625,
0.0,
0.0,
0.25,
0.25
@ -8966,28 +9238,27 @@
"texture"
],
"shortest_path_bound_pipelines": [
"varying"
"varying",
"texture"
],
"shortest_path_cycles": [
0.140625,
0.03125,
0.140625,
0.0625,
0.03125,
0.015625,
0.0,
0.0,
0.25,
0.0
0.25
],
"total_bound_pipelines": [
"arith_total",
"arith_cvt",
"varying",
"texture"
],
"total_cycles": [
0.25,
0.03125,
0.25,
0.0625,
0.03125,
0.015625,
0.0,
0.0,
0.25,
0.25
@ -8996,7 +9267,7 @@
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 4,
"work_registers_used": 7
"work_registers_used": 5
}
}
}
@ -9073,69 +9344,6 @@
}
}
},
"flutter/impeller/entity/uv.comp.vkspv": {
"Mali-G78": {
"core": "Mali-G78",
"filename": "flutter/impeller/entity/uv.comp.vkspv",
"has_uniform_computation": true,
"type": "Compute",
"variants": {
"Main": {
"fp16_arithmetic": 0,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
"load_store"
],
"longest_path_cycles": [
0.1875,
0.1875,
0.125,
0.0625,
2.0,
0.0
],
"pipelines": [
"arith_total",
"arith_fma",
"arith_cvt",
"arith_sfu",
"load_store",
"texture"
],
"shortest_path_bound_pipelines": [
"arith_total",
"arith_cvt"
],
"shortest_path_cycles": [
0.046875,
0.0,
0.046875,
0.0,
0.0,
0.0
],
"total_bound_pipelines": [
"load_store"
],
"total_cycles": [
0.1875,
0.1875,
0.125,
0.0625,
2.0,
0.0
]
},
"shared_storage_used": 0,
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 24,
"work_registers_used": 10
}
}
}
},
"flutter/impeller/entity/vertices.frag.vkspv": {
"Mali-G78": {
"core": "Mali-G78",