[Impeller] remove compute tessellator. (#52584)
We don't have any plans to use this in the near term. The algorithm works but can easily run out of memory, and would need to be entirely reworked to manage memory allocations.
diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files
index 415883a..f4e63b1 100644
--- a/ci/licenses_golden/excluded_files
+++ b/ci/licenses_golden/excluded_files
@@ -184,7 +184,6 @@
../../../flutter/impeller/renderer/backend/vulkan/test
../../../flutter/impeller/renderer/blit_pass_unittests.cc
../../../flutter/impeller/renderer/capabilities_unittests.cc
-../../../flutter/impeller/renderer/compute_subgroup_unittests.cc
../../../flutter/impeller/renderer/compute_unittests.cc
../../../flutter/impeller/renderer/device_buffer_unittests.cc
../../../flutter/impeller/renderer/pipeline_descriptor_unittests.cc
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index eb2bad6..90536fb 100644
--- a/ci/licenses_golden/licenses_flutter
+++ b/ci/licenses_golden/licenses_flutter
@@ -40777,11 +40777,8 @@
ORIGIN: ../../../flutter/impeller/renderer/compute_pipeline_builder.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/compute_pipeline_descriptor.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/compute_pipeline_descriptor.h + ../../../flutter/LICENSE
-ORIGIN: ../../../flutter/impeller/renderer/compute_tessellator.cc + ../../../flutter/LICENSE
-ORIGIN: ../../../flutter/impeller/renderer/compute_tessellator.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/context.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/context.h + ../../../flutter/LICENSE
-ORIGIN: ../../../flutter/impeller/renderer/path_polyline.comp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/pipeline.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/pipeline.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/pipeline_builder.cc + ../../../flutter/LICENSE
@@ -40809,7 +40806,6 @@
ORIGIN: ../../../flutter/impeller/renderer/shader_stage_compatibility_checker.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/snapshot.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/snapshot.h + ../../../flutter/LICENSE
-ORIGIN: ../../../flutter/impeller/renderer/stroke.comp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/surface.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/surface.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/texture_mipmap.cc + ../../../flutter/LICENSE
@@ -43657,11 +43653,8 @@
FILE: ../../../flutter/impeller/renderer/compute_pipeline_builder.h
FILE: ../../../flutter/impeller/renderer/compute_pipeline_descriptor.cc
FILE: ../../../flutter/impeller/renderer/compute_pipeline_descriptor.h
-FILE: ../../../flutter/impeller/renderer/compute_tessellator.cc
-FILE: ../../../flutter/impeller/renderer/compute_tessellator.h
FILE: ../../../flutter/impeller/renderer/context.cc
FILE: ../../../flutter/impeller/renderer/context.h
-FILE: ../../../flutter/impeller/renderer/path_polyline.comp
FILE: ../../../flutter/impeller/renderer/pipeline.cc
FILE: ../../../flutter/impeller/renderer/pipeline.h
FILE: ../../../flutter/impeller/renderer/pipeline_builder.cc
@@ -43689,7 +43682,6 @@
FILE: ../../../flutter/impeller/renderer/shader_stage_compatibility_checker.h
FILE: ../../../flutter/impeller/renderer/snapshot.cc
FILE: ../../../flutter/impeller/renderer/snapshot.h
-FILE: ../../../flutter/impeller/renderer/stroke.comp
FILE: ../../../flutter/impeller/renderer/surface.cc
FILE: ../../../flutter/impeller/renderer/surface.h
FILE: ../../../flutter/impeller/renderer/texture_mipmap.cc
diff --git a/impeller/BUILD.gn b/impeller/BUILD.gn
index accabd9..8e7aee9 100644
--- a/impeller/BUILD.gn
+++ b/impeller/BUILD.gn
@@ -113,10 +113,6 @@
"//third_party/vulkan_validation_layers:vulkan_gen_json_files",
]
}
-
- if (impeller_enable_compute) {
- deps += [ "renderer:compute_tessellation_unittests" ]
- }
}
if (impeller_supports_rendering) {
diff --git a/impeller/entity/contents/solid_color_contents.h b/impeller/entity/contents/solid_color_contents.h
index 59358ac..db5abdd 100644
--- a/impeller/entity/contents/solid_color_contents.h
+++ b/impeller/entity/contents/solid_color_contents.h
@@ -14,10 +14,6 @@
namespace impeller {
-class Path;
-class HostBuffer;
-struct VertexBuffer;
-
class SolidColorContents final : public ColorSourceContents {
public:
SolidColorContents();
diff --git a/impeller/geometry/gradient.h b/impeller/geometry/gradient.h
index 8d6e70a..551ec12 100644
--- a/impeller/geometry/gradient.h
+++ b/impeller/geometry/gradient.h
@@ -6,12 +6,9 @@
#define FLUTTER_IMPELLER_GEOMETRY_GRADIENT_H_
#include <cstdint>
-#include <memory>
#include <vector>
#include "impeller/geometry/color.h"
-#include "impeller/geometry/path.h"
-#include "impeller/geometry/point.h"
namespace impeller {
diff --git a/impeller/renderer/BUILD.gn b/impeller/renderer/BUILD.gn
index 368c037..5ffb79e 100644
--- a/impeller/renderer/BUILD.gn
+++ b/impeller/renderer/BUILD.gn
@@ -20,27 +20,10 @@
}
shaders = [
- "stroke.comp",
- "path_polyline.comp",
"prefix_sum_test.comp",
"threadgroup_sizing_test.comp",
]
}
-
- impeller_component("compute_tessellation_unittests") {
- testonly = true
- sources = [ "compute_subgroup_unittests.cc" ]
-
- deps = [
- ":compute_shaders",
- ":renderer",
- "../display_list:skia_conversions",
- "../entity",
- "../fixtures",
- "../playground:playground_test",
- "//flutter/testing:testing_lib",
- ]
- }
}
impeller_component("renderer") {
@@ -109,10 +92,6 @@
]
if (impeller_enable_compute) {
- sources += [
- "compute_tessellator.cc",
- "compute_tessellator.h",
- ]
public_deps += [ ":compute_shaders" ]
}
diff --git a/impeller/renderer/compute_subgroup_unittests.cc b/impeller/renderer/compute_subgroup_unittests.cc
deleted file mode 100644
index c34a531..0000000
--- a/impeller/renderer/compute_subgroup_unittests.cc
+++ /dev/null
@@ -1,473 +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 <future>
-#include <numeric>
-
-#include "compute_tessellator.h"
-#include "flutter/fml/synchronization/waitable_event.h"
-#include "flutter/fml/time/time_point.h"
-#include "flutter/testing/testing.h"
-#include "gmock/gmock.h"
-#include "impeller/base/strings.h"
-#include "impeller/core/formats.h"
-#include "impeller/core/host_buffer.h"
-#include "impeller/display_list/skia_conversions.h"
-#include "impeller/entity/contents/content_context.h"
-#include "impeller/fixtures/golden_paths.h"
-#include "impeller/fixtures/sample.comp.h"
-#include "impeller/fixtures/stage1.comp.h"
-#include "impeller/fixtures/stage2.comp.h"
-#include "impeller/geometry/path.h"
-#include "impeller/geometry/path_builder.h"
-#include "impeller/geometry/path_component.h"
-#include "impeller/playground/compute_playground_test.h"
-#include "impeller/renderer/command_buffer.h"
-#include "impeller/renderer/compute_pipeline_builder.h"
-#include "impeller/renderer/compute_tessellator.h"
-#include "impeller/renderer/path_polyline.comp.h"
-#include "impeller/renderer/pipeline_library.h"
-#include "impeller/renderer/render_pass.h"
-#include "impeller/renderer/stroke.comp.h"
-#include "third_party/imgui/imgui.h"
-#include "third_party/skia/include/utils/SkParsePath.h"
-
-namespace impeller {
-namespace testing {
-
-using ComputeSubgroupTest = ComputePlaygroundTest;
-INSTANTIATE_COMPUTE_SUITE(ComputeSubgroupTest);
-
-TEST_P(ComputeSubgroupTest, CapabilitiesSuportSubgroups) {
- auto context = GetContext();
- ASSERT_TRUE(context);
- ASSERT_TRUE(context->GetCapabilities()->SupportsComputeSubgroups());
-}
-
-TEST_P(ComputeSubgroupTest, PathPlayground) {
- // Renders stroked SVG paths in an interactive playground.
- using SS = StrokeComputeShader;
-
- auto context = GetContext();
- ASSERT_TRUE(context);
- ASSERT_TRUE(context->GetCapabilities()->SupportsComputeSubgroups());
- char svg_path_data[16384] =
- "M140 20 "
- "C73 20 20 74 20 140 "
- "c0 135 136 170 228 303 "
- "88-132 229-173 229-303 "
- "0-66-54-120-120-120 "
- "-48 0-90 28-109 69 "
- "-19-41-60-69-108-69z";
- size_t vertex_count = 0;
- Scalar stroke_width = 1.0;
-
- auto vertex_buffer = CreateHostVisibleDeviceBuffer<SS::VertexBuffer<2048>>(
- context, "VertexBuffer");
- auto vertex_buffer_count =
- CreateHostVisibleDeviceBuffer<SS::VertexBufferCount>(context,
- "VertexCount");
-
- auto callback = [&](RenderPass& pass) -> bool {
- ::memset(vertex_buffer_count->OnGetContents(), 0,
- sizeof(SS::VertexBufferCount));
- ::memset(vertex_buffer->OnGetContents(), 0, sizeof(SS::VertexBuffer<2048>));
- const auto* main_viewport = ImGui::GetMainViewport();
- ImGui::SetNextWindowPos(
- ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20));
- ImGui::Begin("Path data", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
- ImGui::InputTextMultiline("Path", svg_path_data,
- IM_ARRAYSIZE(svg_path_data));
- ImGui::DragFloat("Stroke width", &stroke_width, .1, 0.0, 25.0);
-
- SkPath sk_path;
- if (SkParsePath::FromSVGString(svg_path_data, &sk_path)) {
- std::promise<bool> promise;
- auto future = promise.get_future();
-
- auto path = skia_conversions::ToPath(sk_path);
- auto host_buffer = HostBuffer::Create(context->GetResourceAllocator());
- auto status =
- ComputeTessellator{}
- .SetStrokeWidth(stroke_width)
- .Tessellate(path, *host_buffer, context,
- DeviceBuffer::AsBufferView(vertex_buffer),
- DeviceBuffer::AsBufferView(vertex_buffer_count),
- [vertex_buffer_count, &vertex_count,
- &promise](CommandBuffer::Status status) {
- vertex_count =
- reinterpret_cast<SS::VertexBufferCount*>(
- vertex_buffer_count->OnGetContents())
- ->count;
- promise.set_value(
- status == CommandBuffer::Status::kCompleted);
- });
- switch (status) {
- case ComputeTessellator::Status::kCommandInvalid:
- ImGui::Text("Failed to submit compute job (invalid command)");
- break;
- case ComputeTessellator::Status::kTooManyComponents:
- ImGui::Text("Failed to submit compute job (too many components) ");
- break;
- case ComputeTessellator::Status::kOk:
- break;
- }
- if (!future.get()) {
- ImGui::Text("Failed to submit compute job.");
- return false;
- }
- if (vertex_count > 0) {
- ImGui::Text("Vertex count: %zu", vertex_count);
- }
- } else {
- ImGui::Text("Failed to parse path data");
- }
- ImGui::End();
-
- ContentContext renderer(context, nullptr);
- if (!renderer.IsValid()) {
- return false;
- }
-
- using VS = SolidFillPipeline::VertexShader;
-
- pass.SetCommandLabel("Draw Stroke");
- pass.SetStencilReference(0);
-
- ContentContextOptions options;
- options.sample_count = pass.GetRenderTarget().GetSampleCount();
- options.color_attachment_pixel_format =
- pass.GetRenderTarget().GetRenderTargetPixelFormat();
- options.has_depth_stencil_attachments =
- pass.GetRenderTarget().GetStencilAttachment().has_value();
- options.blend_mode = BlendMode::kSourceIn;
- options.primitive_type = PrimitiveType::kTriangleStrip;
-
- options.stencil_mode =
- ContentContextOptions::StencilMode::kOverdrawPreventionIncrement;
-
- pass.SetPipeline(renderer.GetSolidFillPipeline(options));
-
- auto count = reinterpret_cast<SS::VertexBufferCount*>(
- vertex_buffer_count->OnGetContents())
- ->count;
-
- pass.SetVertexBuffer(
- VertexBuffer{.vertex_buffer = DeviceBuffer::AsBufferView(vertex_buffer),
- .vertex_count = count,
- .index_type = IndexType::kNone});
-
- VS::FrameInfo frame_info;
- auto world_matrix = Matrix::MakeScale(GetContentScale());
- frame_info.mvp = pass.GetOrthographicTransform() * world_matrix;
- frame_info.color = Color::Red().Premultiply();
- VS::BindFrameInfo(
- pass, renderer.GetTransientsBuffer().EmplaceUniform(frame_info));
-
- return pass.Draw().ok();
- };
- ASSERT_TRUE(OpenPlaygroundHere(callback));
-}
-
-TEST_P(ComputeSubgroupTest, LargePath) {
- // The path in here is large enough to highlight issues around exceeding
- // subgroup size.
- using SS = StrokeComputeShader;
-
- auto context = GetContext();
- ASSERT_TRUE(context);
- ASSERT_TRUE(context->GetCapabilities()->SupportsComputeSubgroups());
- size_t vertex_count = 0;
- Scalar stroke_width = 1.0;
-
- auto vertex_buffer = CreateHostVisibleDeviceBuffer<SS::VertexBuffer<2048>>(
- context, "VertexBuffer");
- auto vertex_buffer_count =
- CreateHostVisibleDeviceBuffer<SS::VertexBufferCount>(context,
- "VertexCount");
-
- auto complex_path =
- PathBuilder{}
- .MoveTo({359.934, 96.6335})
- .CubicCurveTo({358.189, 96.7055}, {356.436, 96.7908},
- {354.673, 96.8895})
- .CubicCurveTo({354.571, 96.8953}, {354.469, 96.9016},
- {354.367, 96.9075})
- .CubicCurveTo({352.672, 97.0038}, {350.969, 97.113},
- {349.259, 97.2355})
- .CubicCurveTo({349.048, 97.2506}, {348.836, 97.2678},
- {348.625, 97.2834})
- .CubicCurveTo({347.019, 97.4014}, {345.407, 97.5299},
- {343.789, 97.6722})
- .CubicCurveTo({343.428, 97.704}, {343.065, 97.7402},
- {342.703, 97.7734})
- .CubicCurveTo({341.221, 97.9086}, {339.736, 98.0505},
- {338.246, 98.207})
- .CubicCurveTo({337.702, 98.2642}, {337.156, 98.3292},
- {336.612, 98.3894})
- .CubicCurveTo({335.284, 98.5356}, {333.956, 98.6837},
- {332.623, 98.8476})
- .CubicCurveTo({332.495, 98.8635}, {332.366, 98.8818},
- {332.237, 98.8982})
- .LineTo({332.237, 102.601})
- .LineTo({321.778, 102.601})
- .LineTo({321.778, 100.382})
- .CubicCurveTo({321.572, 100.413}, {321.367, 100.442},
- {321.161, 100.476})
- .CubicCurveTo({319.22, 100.79}, {317.277, 101.123},
- {315.332, 101.479})
- .CubicCurveTo({315.322, 101.481}, {315.311, 101.482},
- {315.301, 101.484})
- .LineTo({310.017, 105.94})
- .LineTo({309.779, 105.427})
- .LineTo({314.403, 101.651})
- .CubicCurveTo({314.391, 101.653}, {314.379, 101.656},
- {314.368, 101.658})
- .CubicCurveTo({312.528, 102.001}, {310.687, 102.366},
- {308.846, 102.748})
- .CubicCurveTo({307.85, 102.955}, {306.855, 103.182}, {305.859, 103.4})
- .CubicCurveTo({305.048, 103.579}, {304.236, 103.75},
- {303.425, 103.936})
- .LineTo({299.105, 107.578})
- .LineTo({298.867, 107.065})
- .LineTo({302.394, 104.185})
- .LineTo({302.412, 104.171})
- .CubicCurveTo({301.388, 104.409}, {300.366, 104.67},
- {299.344, 104.921})
- .CubicCurveTo({298.618, 105.1}, {297.89, 105.269}, {297.165, 105.455})
- .CubicCurveTo({295.262, 105.94}, {293.36, 106.445},
- {291.462, 106.979})
- .CubicCurveTo({291.132, 107.072}, {290.802, 107.163},
- {290.471, 107.257})
- .CubicCurveTo({289.463, 107.544}, {288.455, 107.839},
- {287.449, 108.139})
- .CubicCurveTo({286.476, 108.431}, {285.506, 108.73},
- {284.536, 109.035})
- .CubicCurveTo({283.674, 109.304}, {282.812, 109.579},
- {281.952, 109.859})
- .CubicCurveTo({281.177, 110.112}, {280.406, 110.377},
- {279.633, 110.638})
- .CubicCurveTo({278.458, 111.037}, {277.256, 111.449},
- {276.803, 111.607})
- .CubicCurveTo({276.76, 111.622}, {276.716, 111.637},
- {276.672, 111.653})
- .CubicCurveTo({275.017, 112.239}, {273.365, 112.836},
- {271.721, 113.463})
- .LineTo({271.717, 113.449})
- .CubicCurveTo({271.496, 113.496}, {271.238, 113.559},
- {270.963, 113.628})
- .CubicCurveTo({270.893, 113.645}, {270.822, 113.663},
- {270.748, 113.682})
- .CubicCurveTo({270.468, 113.755}, {270.169, 113.834},
- {269.839, 113.926})
- .CubicCurveTo({269.789, 113.94}, {269.732, 113.957},
- {269.681, 113.972})
- .CubicCurveTo({269.391, 114.053}, {269.081, 114.143},
- {268.756, 114.239})
- .CubicCurveTo({268.628, 114.276}, {268.5, 114.314},
- {268.367, 114.354})
- .CubicCurveTo({268.172, 114.412}, {267.959, 114.478},
- {267.752, 114.54})
- .CubicCurveTo({263.349, 115.964}, {258.058, 117.695},
- {253.564, 119.252})
- .CubicCurveTo({253.556, 119.255}, {253.547, 119.258},
- {253.538, 119.261})
- .CubicCurveTo({251.844, 119.849}, {250.056, 120.474},
- {248.189, 121.131})
- .CubicCurveTo({248, 121.197}, {247.812, 121.264}, {247.621, 121.331})
- .CubicCurveTo({247.079, 121.522}, {246.531, 121.715},
- {245.975, 121.912})
- .CubicCurveTo({245.554, 122.06}, {245.126, 122.212},
- {244.698, 122.364})
- .CubicCurveTo({244.071, 122.586}, {243.437, 122.811},
- {242.794, 123.04})
- .CubicCurveTo({242.189, 123.255}, {241.58, 123.472},
- {240.961, 123.693})
- .CubicCurveTo({240.659, 123.801}, {240.357, 123.909},
- {240.052, 124.018})
- .CubicCurveTo({239.12, 124.351}, {238.18, 124.687}, {237.22, 125.032})
- .LineTo({237.164, 125.003})
- .CubicCurveTo({236.709, 125.184}, {236.262, 125.358},
- {235.81, 125.538})
- .CubicCurveTo({235.413, 125.68}, {234.994, 125.832},
- {234.592, 125.977})
- .CubicCurveTo({234.592, 125.977}, {234.591, 125.977},
- {234.59, 125.977})
- .CubicCurveTo({222.206, 130.435}, {207.708, 135.753},
- {192.381, 141.429})
- .CubicCurveTo({162.77, 151.336}, {122.17, 156.894}, {84.1123, 160})
- .LineTo({360, 160})
- .LineTo({360, 119.256})
- .LineTo({360, 106.332})
- .LineTo({360, 96.6307})
- .CubicCurveTo({359.978, 96.6317}, {359.956, 96.6326},
- {359.934, 96.6335})
- .Close()
- .TakePath();
-
- auto callback = [&](RenderPass& pass) -> bool {
- ::memset(vertex_buffer_count->OnGetContents(), 0,
- sizeof(SS::VertexBufferCount));
- ::memset(vertex_buffer->OnGetContents(), 0, sizeof(SS::VertexBuffer<2048>));
-
- ContentContext renderer(context, nullptr);
- if (!renderer.IsValid()) {
- return false;
- }
-
- ComputeTessellator{}
- .SetStrokeWidth(stroke_width)
- .Tessellate(
- complex_path, renderer.GetTransientsBuffer(), context,
- DeviceBuffer::AsBufferView(vertex_buffer),
- DeviceBuffer::AsBufferView(vertex_buffer_count),
- [vertex_buffer_count, &vertex_count](CommandBuffer::Status status) {
- vertex_count = reinterpret_cast<SS::VertexBufferCount*>(
- vertex_buffer_count->OnGetContents())
- ->count;
- });
-
- using VS = SolidFillPipeline::VertexShader;
-
- pass.SetCommandLabel("Draw Stroke");
- pass.SetStencilReference(0);
-
- ContentContextOptions options;
- options.sample_count = pass.GetRenderTarget().GetSampleCount();
- options.color_attachment_pixel_format =
- pass.GetRenderTarget().GetRenderTargetPixelFormat();
- options.has_depth_stencil_attachments =
- pass.GetRenderTarget().GetStencilAttachment().has_value();
- options.blend_mode = BlendMode::kSourceIn;
- options.primitive_type = PrimitiveType::kTriangleStrip;
-
- options.stencil_mode =
- ContentContextOptions::StencilMode::kOverdrawPreventionIncrement;
-
- pass.SetPipeline(renderer.GetSolidFillPipeline(options));
-
- auto count = reinterpret_cast<SS::VertexBufferCount*>(
- vertex_buffer_count->OnGetContents())
- ->count;
-
- pass.SetVertexBuffer(
- VertexBuffer{.vertex_buffer = DeviceBuffer::AsBufferView(vertex_buffer),
- .vertex_count = count,
- .index_type = IndexType::kNone});
-
- VS::FrameInfo frame_info;
- auto world_matrix = Matrix::MakeScale(GetContentScale());
- frame_info.mvp = pass.GetOrthographicTransform() * world_matrix;
- frame_info.color = Color::Red().Premultiply();
- VS::BindFrameInfo(
- pass, renderer.GetTransientsBuffer().EmplaceUniform(frame_info));
-
- return pass.Draw().ok();
- };
- ASSERT_TRUE(OpenPlaygroundHere(callback));
-}
-
-TEST_P(ComputeSubgroupTest, QuadAndCubicInOnePath) {
- using SS = StrokeComputeShader;
-
- auto context = GetContext();
- ASSERT_TRUE(context);
- ASSERT_TRUE(context->GetCapabilities()->SupportsComputeSubgroups());
-
- auto vertex_buffer = CreateHostVisibleDeviceBuffer<SS::VertexBuffer<2048>>(
- context, "VertexBuffer");
- auto vertex_buffer_count =
- CreateHostVisibleDeviceBuffer<SS::VertexBufferCount>(context,
- "VertexBufferCount");
-
- auto path = PathBuilder{}
- .AddCubicCurve({140, 20}, {73, 20}, {20, 74}, {20, 140})
- .AddQuadraticCurve({20, 140}, {93, 90}, {100, 42})
- .TakePath();
-
- auto tessellator = ComputeTessellator{};
-
- fml::AutoResetWaitableEvent latch;
-
- auto host_buffer = HostBuffer::Create(context->GetResourceAllocator());
- auto status = tessellator.Tessellate(
- path, *host_buffer, context, DeviceBuffer::AsBufferView(vertex_buffer),
- DeviceBuffer::AsBufferView(vertex_buffer_count),
- [&latch](CommandBuffer::Status status) {
- EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
- latch.Signal();
- });
-
- ASSERT_EQ(status, ComputeTessellator::Status::kOk);
-
- auto callback = [&](RenderPass& pass) -> bool {
- ContentContext renderer(context, nullptr);
- if (!renderer.IsValid()) {
- return false;
- }
-
- using VS = SolidFillPipeline::VertexShader;
-
- pass.SetCommandLabel("Draw Stroke");
- pass.SetStencilReference(0);
-
- ContentContextOptions options;
- options.sample_count = pass.GetRenderTarget().GetSampleCount();
- options.color_attachment_pixel_format =
- pass.GetRenderTarget().GetRenderTargetPixelFormat();
- options.has_depth_stencil_attachments =
- pass.GetRenderTarget().GetStencilAttachment().has_value();
- options.blend_mode = BlendMode::kSourceIn;
- options.primitive_type = PrimitiveType::kTriangleStrip;
-
- options.stencil_mode =
- ContentContextOptions::StencilMode::kOverdrawPreventionIncrement;
-
- pass.SetPipeline(renderer.GetSolidFillPipeline(options));
-
- auto count = reinterpret_cast<SS::VertexBufferCount*>(
- vertex_buffer_count->OnGetContents())
- ->count;
-
- pass.SetVertexBuffer(
- VertexBuffer{.vertex_buffer = DeviceBuffer::AsBufferView(vertex_buffer),
- .vertex_count = count,
- .index_type = IndexType::kNone});
-
- VS::FrameInfo frame_info;
- auto world_matrix = Matrix::MakeScale(GetContentScale());
- frame_info.mvp = pass.GetOrthographicTransform() * world_matrix;
- frame_info.color = Color::Red().Premultiply();
- VS::BindFrameInfo(
- pass, renderer.GetTransientsBuffer().EmplaceUniform(frame_info));
-
- return pass.Draw().ok();
- };
- ASSERT_TRUE(OpenPlaygroundHere(callback));
-
- // The latch is down here because it's expected that on Metal the backend
- // will take care of synchronizing the buffer between the compute and render
- // pass usages, since it's not MTLHeap allocated. However, if playgrounds
- // are disabled, no render pass actually gets submitted and we need to do a
- // CPU latch here.
- latch.Wait();
-
- auto vertex_count = reinterpret_cast<SS::VertexBufferCount*>(
- vertex_buffer_count->OnGetContents())
- ->count;
- EXPECT_EQ(vertex_count, golden_cubic_and_quad_points.size());
- auto vertex_buffer_data =
- reinterpret_cast<SS::VertexBuffer<2048>*>(vertex_buffer->OnGetContents());
- for (size_t i = 0; i < vertex_count; i++) {
- EXPECT_LT(std::abs(golden_cubic_and_quad_points[i].x -
- vertex_buffer_data->position[i].x),
- 1e-3);
- EXPECT_LT(std::abs(golden_cubic_and_quad_points[i].y -
- vertex_buffer_data->position[i].y),
- 1e-3);
- }
-}
-
-} // namespace testing
-} // namespace impeller
diff --git a/impeller/renderer/compute_tessellator.cc b/impeller/renderer/compute_tessellator.cc
deleted file mode 100644
index 8e8d084..0000000
--- a/impeller/renderer/compute_tessellator.cc
+++ /dev/null
@@ -1,181 +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/renderer/compute_tessellator.h"
-
-#include <cstdint>
-
-#include "impeller/core/host_buffer.h"
-#include "impeller/renderer/command_buffer.h"
-#include "impeller/renderer/path_polyline.comp.h"
-#include "impeller/renderer/pipeline_library.h"
-#include "impeller/renderer/stroke.comp.h"
-
-namespace impeller {
-
-ComputeTessellator::ComputeTessellator() = default;
-ComputeTessellator::~ComputeTessellator() = default;
-
-template <typename T>
-static std::shared_ptr<DeviceBuffer> CreateDeviceBuffer(
- const std::shared_ptr<Context>& context,
- const std::string& label,
- StorageMode storage_mode = StorageMode::kDevicePrivate) {
- DeviceBufferDescriptor desc;
- desc.storage_mode = storage_mode;
- desc.size = sizeof(T);
- auto buffer = context->GetResourceAllocator()->CreateBuffer(desc);
- buffer->SetLabel(label);
- return buffer;
-}
-
-ComputeTessellator& ComputeTessellator::SetStyle(Style value) {
- style_ = value;
- return *this;
-}
-
-ComputeTessellator& ComputeTessellator::SetStrokeWidth(Scalar value) {
- stroke_width_ = value;
- return *this;
-}
-
-ComputeTessellator& ComputeTessellator::SetStrokeJoin(Join value) {
- stroke_join_ = value;
- return *this;
-}
-ComputeTessellator& ComputeTessellator::SetStrokeCap(Cap value) {
- stroke_cap_ = value;
- return *this;
-}
-ComputeTessellator& ComputeTessellator::SetMiterLimit(Scalar value) {
- miter_limit_ = value;
- return *this;
-}
-ComputeTessellator& ComputeTessellator::SetCubicAccuracy(Scalar value) {
- cubic_accuracy_ = value;
- return *this;
-}
-ComputeTessellator& ComputeTessellator::SetQuadraticTolerance(Scalar value) {
- quad_tolerance_ = value;
- return *this;
-}
-
-ComputeTessellator::Status ComputeTessellator::Tessellate(
- const Path& path,
- HostBuffer& host_buffer,
- const std::shared_ptr<Context>& context,
- BufferView vertex_buffer,
- BufferView vertex_buffer_count,
- const CommandBuffer::CompletionCallback& callback) const {
- FML_DCHECK(style_ == Style::kStroke);
- using PS = PathPolylineComputeShader;
- using SS = StrokeComputeShader;
-
- auto cubic_count = path.GetComponentCount(Path::ComponentType::kCubic);
- auto quad_count = path.GetComponentCount(Path::ComponentType::kQuadratic) +
- (cubic_count * 6);
- auto line_count =
- path.GetComponentCount(Path::ComponentType::kLinear) + (quad_count * 6);
- if (cubic_count > kMaxCubicCount || quad_count > kMaxQuadCount ||
- line_count > kMaxLineCount) {
- return Status::kTooManyComponents;
- }
- PS::Cubics<kMaxCubicCount> cubics{.count = 0};
- PS::Quads<kMaxQuadCount> quads{.count = 0};
- PS::Lines<kMaxLineCount> lines{.count = 0};
- PS::Components<kMaxComponentCount> components{.count = 0};
- PS::Config config{.cubic_accuracy = cubic_accuracy_,
- .quad_tolerance = quad_tolerance_};
-
- path.EnumerateComponents(
- [&lines, &components](size_t index, const LinearPathComponent& linear) {
- ::memcpy(&lines.data[lines.count], &linear,
- sizeof(LinearPathComponent));
- components.data[components.count++] = {lines.count++, 2};
- },
- [&quads, &components](size_t index, const QuadraticPathComponent& quad) {
- ::memcpy(&quads.data[quads.count], &quad,
- sizeof(QuadraticPathComponent));
- components.data[components.count++] = {quads.count++, 3};
- },
- [&cubics, &components](size_t index, const CubicPathComponent& cubic) {
- ::memcpy(&cubics.data[cubics.count], &cubic,
- sizeof(CubicPathComponent));
- components.data[components.count++] = {cubics.count++, 4};
- },
- [](size_t index, const ContourComponent& contour) {});
-
- auto polyline_buffer =
- CreateDeviceBuffer<PS::Polyline<2048>>(context, "Polyline");
-
- auto cmd_buffer = context->CreateCommandBuffer();
- auto pass = cmd_buffer->CreateComputePass();
- FML_DCHECK(pass && pass->IsValid());
-
- {
- using PathPolylinePipelineBuilder = ComputePipelineBuilder<PS>;
- auto pipeline_desc =
- PathPolylinePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
- FML_DCHECK(pipeline_desc.has_value());
- auto compute_pipeline =
- context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
- FML_DCHECK(compute_pipeline);
-
- pass->SetPipeline(compute_pipeline);
- pass->SetCommandLabel("Generate Polyline");
-
- PS::BindConfig(*pass, host_buffer.EmplaceUniform(config));
- PS::BindCubics(*pass, host_buffer.EmplaceStorageBuffer(cubics));
- PS::BindQuads(*pass, host_buffer.EmplaceStorageBuffer(quads));
- PS::BindLines(*pass, host_buffer.EmplaceStorageBuffer(lines));
- PS::BindComponents(*pass, host_buffer.EmplaceStorageBuffer(components));
- PS::BindPolyline(*pass, DeviceBuffer::AsBufferView(polyline_buffer));
-
- if (!pass->Compute(ISize(line_count, 1)).ok()) {
- return Status::kCommandInvalid;
- }
- }
-
- {
- using StrokePipelineBuilder = ComputePipelineBuilder<SS>;
- auto pipeline_desc =
- StrokePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
- FML_DCHECK(pipeline_desc.has_value());
- auto compute_pipeline =
- context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
- FML_DCHECK(compute_pipeline);
-
- pass->AddBufferMemoryBarrier();
- pass->SetPipeline(compute_pipeline);
- pass->SetCommandLabel("Compute Stroke");
-
- SS::Config config{
- .width = stroke_width_,
- .cap = static_cast<uint32_t>(stroke_cap_),
- .join = static_cast<uint32_t>(stroke_join_),
- .miter_limit = miter_limit_,
- };
- SS::BindConfig(*pass, host_buffer.EmplaceUniform(config));
-
- SS::BindPolyline(*pass, DeviceBuffer::AsBufferView(polyline_buffer));
- SS::BindVertexBufferCount(*pass, std::move(vertex_buffer_count));
- SS::BindVertexBuffer(*pass, std::move(vertex_buffer));
-
- if (!pass->Compute(ISize(line_count, 1)).ok()) {
- return Status::kCommandInvalid;
- }
- }
-
- if (!pass->EncodeCommands()) {
- return Status::kCommandInvalid;
- }
-
- if (!context->GetCommandQueue()->Submit({cmd_buffer}, callback).ok()) {
- return Status::kCommandInvalid;
- }
-
- return Status::kOk;
-}
-
-} // namespace impeller
diff --git a/impeller/renderer/compute_tessellator.h b/impeller/renderer/compute_tessellator.h
deleted file mode 100644
index a74c54e..0000000
--- a/impeller/renderer/compute_tessellator.h
+++ /dev/null
@@ -1,89 +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.
-
-#ifndef FLUTTER_IMPELLER_RENDERER_COMPUTE_TESSELLATOR_H_
-#define FLUTTER_IMPELLER_RENDERER_COMPUTE_TESSELLATOR_H_
-
-#include "impeller/core/buffer_view.h"
-#include "impeller/geometry/path.h"
-#include "impeller/renderer/command_buffer.h"
-#include "impeller/renderer/context.h"
-
-namespace impeller {
-
-//------------------------------------------------------------------------------
-/// @brief A utility that generates triangles of the specified fill type
-/// given a path.
-///
-class ComputeTessellator {
- public:
- ComputeTessellator();
-
- ~ComputeTessellator();
-
- static constexpr size_t kMaxCubicCount = 512;
- static constexpr size_t kMaxQuadCount = 2048;
- static constexpr size_t kMaxLineCount = 4096;
- static constexpr size_t kMaxComponentCount =
- kMaxCubicCount + kMaxQuadCount + kMaxLineCount;
-
- enum class Status {
- kCommandInvalid,
- kTooManyComponents,
- kOk,
- };
-
- enum class Style {
- kStroke,
- // TODO(dnfield): Implement kFill.
- };
-
- ComputeTessellator& SetStyle(Style value);
- ComputeTessellator& SetStrokeWidth(Scalar value);
- ComputeTessellator& SetStrokeJoin(Join value);
- ComputeTessellator& SetStrokeCap(Cap value);
- ComputeTessellator& SetMiterLimit(Scalar value);
- ComputeTessellator& SetCubicAccuracy(Scalar value);
- ComputeTessellator& SetQuadraticTolerance(Scalar value);
-
- //----------------------------------------------------------------------------
- /// @brief Generates triangles from the path.
- /// If the data needs to be synchronized back to the CPU, e.g.
- /// because one of the buffer views are host visible and will be
- /// used without creating a blit pass to copy them back, the
- /// callback is used to determine when the GPU calculation is
- /// complete and its status.
- /// On Metal, no additional synchronization is needed as long as
- /// the buffers are not heap allocated, so no additional
- /// synchronization mechanism is provided.
- ///
- /// @return A |Status| value indicating success or failure of the submission.
- ///
- // TODO(dnfield): Provide additional synchronization methods here for Vulkan
- // and heap allocated buffers on Metal.
- Status Tessellate(
- const Path& path,
- HostBuffer& host_buffer,
- const std::shared_ptr<Context>& context,
- BufferView vertex_buffer,
- BufferView vertex_buffer_count,
- const CommandBuffer::CompletionCallback& callback = nullptr) const;
-
- private:
- Style style_ = Style::kStroke;
- Scalar stroke_width_ = 1.0f;
- Cap stroke_cap_ = Cap::kButt;
- Join stroke_join_ = Join::kMiter;
- Scalar miter_limit_ = 4.0f;
- Scalar cubic_accuracy_ = .1f;
- Scalar quad_tolerance_ = .1f;
-
- ComputeTessellator(const ComputeTessellator&) = delete;
-
- ComputeTessellator& operator=(const ComputeTessellator&) = delete;
-};
-
-} // namespace impeller
-
-#endif // FLUTTER_IMPELLER_RENDERER_COMPUTE_TESSELLATOR_H_
diff --git a/impeller/renderer/path_polyline.comp b/impeller/renderer/path_polyline.comp
deleted file mode 100644
index 0804c8f..0000000
--- a/impeller/renderer/path_polyline.comp
+++ /dev/null
@@ -1,170 +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.
-#extension GL_KHR_shader_subgroup_arithmetic : enable
-
-layout(local_size_x = 256, local_size_y = 1) in;
-layout(std430) buffer;
-
-#include <impeller/path.glsl>
-
-layout(binding = 0) readonly buffer Cubics {
- uint count;
- CubicData data[];
-}
-cubics;
-
-layout(binding = 1) buffer Quads {
- uint count;
- QuadData data[];
-}
-quads;
-
-layout(binding = 2) buffer Lines {
- uint count;
- LineData data[];
-}
-lines;
-
-layout(binding = 3) buffer Components {
- uint count;
- PathComponent data[];
-}
-components;
-
-layout(binding = 4) buffer Polyline {
- uint count;
- vec2 data[];
-}
-polyline;
-
-uniform Config {
- float cubic_accuracy;
- float quad_tolerance;
-}
-config;
-
-shared uvec2 cubic_ranges[512];
-shared uvec2 quad_ranges[512];
-shared uint scratch_count[512];
-shared uint scratch_sum[512];
-
-uint ComputePosition(uint index) {
- uint sum = scratch_sum[index];
- for (uint position = gl_SubgroupSize - 1; position < index;
- position += gl_SubgroupSize) {
- sum += scratch_sum[position] + scratch_count[position];
- }
- return sum;
-}
-
-void ProcessCubic(uint ident) {
- CubicData cubic;
- uint quad_count = 0;
- if (ident < cubics.count) {
- cubic = cubics.data[ident];
- quad_count = EstimateQuadraticCount(cubic, config.cubic_accuracy);
- scratch_count[ident] = quad_count;
- }
-
- barrier();
-
- uint offset = 0;
- if (quad_count > 0) {
- scratch_sum[ident] = subgroupExclusiveAdd(scratch_count[ident]);
-
- offset = ComputePosition(ident) + quads.count;
- }
- barrier();
- if (quad_count > 0) {
- atomicAdd(quads.count, quad_count);
-
- cubic_ranges[ident] = uvec2(offset, quad_count);
- for (uint i = 0; i < quad_count; i++) {
- quads.data[offset + i] = GenerateQuadraticFromCubic(cubic, i, quad_count);
- }
- }
-}
-
-void ProcessQuad(uint ident) {
- QuadData quad;
- QuadDecomposition decomposition;
- if (ident < quads.count) {
- quad = quads.data[ident];
- decomposition = DecomposeQuad(quad, config.quad_tolerance);
- scratch_count[ident] = decomposition.line_count;
- }
-
- barrier();
-
- uint offset = 0;
- if (decomposition.line_count > 0) {
- scratch_sum[ident] = subgroupExclusiveAdd(scratch_count[ident]);
- offset = ComputePosition(ident) + lines.count;
- }
- barrier();
-
- if (decomposition.line_count > 0) {
- atomicAdd(lines.count, decomposition.line_count);
- quad_ranges[ident] = uvec2(offset, decomposition.line_count);
-
- vec2 last_point = quad.p1;
- for (uint i = 1; i < decomposition.line_count; i++) {
- LineData line =
- LineData(last_point, GenerateLineFromQuad(quad, i, decomposition));
- last_point = line.p2;
- lines.data[offset + i - 1] = line;
- }
- lines.data[offset + decomposition.line_count - 1] =
- LineData(last_point, quad.p2);
- }
-}
-
-void ProcessLine(uint ident) {
- if (ident == 0) {
- polyline.count = lines.count + 1;
- }
-
- PathComponent component;
- uvec2 range = uvec2(0, 0);
- if (ident < components.count) {
- component = components.data[ident];
- if (component.count == 4) {
- // Determine location in quads
- uvec2 quad_range = cubic_ranges[component.index];
- uvec2 end_range = quad_ranges[quad_range.x + quad_range.y - 1];
- range.x = quad_ranges[quad_range.x].x;
- range.y = end_range.x + end_range.y - range.x;
- } else if (component.count == 3) {
- range = quad_ranges[component.index];
- } else if (component.count == 2) {
- range = uvec2(component.index, 1);
- }
-
- scratch_count[ident] = range.y;
- }
- barrier();
-
- if (ident < components.count) {
- scratch_sum[ident] = subgroupExclusiveAdd(scratch_count[ident]);
- uint offset = ComputePosition(ident);
- polyline.data[offset] = lines.data[range.x].p1;
- for (uint i = 0; i < range.y; i++) {
- polyline.data[offset + i + 1] = lines.data[range.x + i].p2;
- }
- }
-}
-
-void main() {
- uint ident = gl_GlobalInvocationID.x;
- // Turn each cubic into quads.
- ProcessCubic(ident);
- barrier();
-
- // Turn each quad into lines.
- ProcessQuad(ident);
- barrier();
-
- // Copy lines to the output buffer.
- ProcessLine(ident);
-}
diff --git a/impeller/renderer/stroke.comp b/impeller/renderer/stroke.comp
deleted file mode 100644
index 5d9cf55..0000000
--- a/impeller/renderer/stroke.comp
+++ /dev/null
@@ -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.
-#extension GL_KHR_shader_subgroup_arithmetic : enable
-
-layout(local_size_x = 256, local_size_y = 1) in;
-layout(std430) buffer;
-
-layout(binding = 0) buffer Polyline {
- uint count;
- vec2 data[];
-}
-polyline;
-
-layout(binding = 1) buffer VertexBuffer {
- vec2 position[];
-}
-vertex_buffer;
-
-layout(binding = 2) buffer VertexBufferCount {
- uint count;
-}
-vertex_buffer_count;
-
-uniform Config {
- float width;
- uint cap;
- uint join;
- float miter_limit;
-}
-config;
-
-vec2 compute_offset(uint index) {
- vec2 direction = normalize(polyline.data[index + 1] - polyline.data[index]);
- return vec2(-direction.y, direction.x) * config.width * .5;
-}
-
-void main() {
- uint ident = gl_GlobalInvocationID.x;
- if (ident >= polyline.count || ident == 0) {
- // This is ok because there is no barrier() below.
- return;
- }
-
- atomicAdd(vertex_buffer_count.count, 4);
-
- uint index = ident - 1;
- vec2 offset = compute_offset(index);
- vertex_buffer.position[index * 4 + 0] = polyline.data[ident - 1] + offset;
- vertex_buffer.position[index * 4 + 1] = polyline.data[ident - 1] - offset;
- vertex_buffer.position[index * 4 + 2] = polyline.data[ident] + offset;
- vertex_buffer.position[index * 4 + 3] = polyline.data[ident] - offset;
-
- // TODO(dnfield): Implement other cap/join mechanisms.
- if (ident == polyline.count - 1) {
- vertex_buffer.position[index * 4 + 4] = polyline.data[ident] + offset;
- vertex_buffer.position[index * 4 + 5] = polyline.data[ident] - offset;
- atomicAdd(vertex_buffer_count.count, 2);
- }
-}
diff --git a/impeller/tools/malioc.json b/impeller/tools/malioc.json
index 856dc2c..35b83ea 100644
--- a/impeller/tools/malioc.json
+++ b/impeller/tools/malioc.json
@@ -7622,68 +7622,6 @@
}
}
},
- "flutter/impeller/renderer/path_polyline.comp.vkspv": {
- "Mali-G78": {
- "core": "Mali-G78",
- "filename": "flutter/impeller/renderer/path_polyline.comp.vkspv",
- "has_uniform_computation": true,
- "type": "Compute",
- "variants": {
- "Main": {
- "fp16_arithmetic": 0,
- "has_stack_spilling": false,
- "performance": {
- "longest_path_bound_pipelines": [
- null
- ],
- "longest_path_cycles": [
- null,
- null,
- null,
- null,
- null,
- null
- ],
- "pipelines": [
- "arith_total",
- "arith_fma",
- "arith_cvt",
- "arith_sfu",
- "load_store",
- "texture"
- ],
- "shortest_path_bound_pipelines": [
- "load_store"
- ],
- "shortest_path_cycles": [
- 0.609375,
- 0.0,
- 0.609375,
- 0.3125,
- 4.0,
- 0.0
- ],
- "total_bound_pipelines": [
- "load_store"
- ],
- "total_cycles": [
- 5.9375,
- 2.737499952316284,
- 4.987500190734863,
- 5.9375,
- 37.20000076293945,
- 0.0
- ]
- },
- "shared_storage_used": 12288,
- "stack_spill_bytes": 0,
- "thread_occupancy": 50,
- "uniform_registers_used": 32,
- "work_registers_used": 51
- }
- }
- }
- },
"flutter/impeller/renderer/prefix_sum_test.comp.vkspv": {
"Mali-G78": {
"core": "Mali-G78",
@@ -7747,69 +7685,6 @@
}
}
},
- "flutter/impeller/renderer/stroke.comp.vkspv": {
- "Mali-G78": {
- "core": "Mali-G78",
- "filename": "flutter/impeller/renderer/stroke.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.3125,
- 0.3125,
- 0.1875,
- 0.125,
- 7.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.0625,
- 0.0,
- 0.0625,
- 0.0,
- 0.0,
- 0.0
- ],
- "total_bound_pipelines": [
- "load_store"
- ],
- "total_cycles": [
- 0.3125,
- 0.3125,
- 0.1875,
- 0.125,
- 7.0,
- 0.0
- ]
- },
- "shared_storage_used": 0,
- "stack_spill_bytes": 0,
- "thread_occupancy": 100,
- "uniform_registers_used": 10,
- "work_registers_used": 24
- }
- }
- }
- },
"flutter/impeller/renderer/threadgroup_sizing_test.comp.vkspv": {
"Mali-G78": {
"core": "Mali-G78",