[Impeller] Reland: Remove Entity capture/AiksInspector. (flutter/engine#52932)

Resolves https://github.com/flutter/flutter/issues/134748.

This was a really fun experiment. I learned a lot from it, and it
genuinely helped me solve some coverage-related problems, but the
reality is it was too little too late -- by the time we had this
capture system, we had already solved most of the problems that would
have benefitted from this.

It's been a few months since I've used or extended the capabilities of
this capture system for something, and I don't have the spare
time/energy to give it the love it needs to realize the vision I had
for it. I still almost exclusively use a combination of native frame
captures and print debugging to solve problems.

RIP in peace.

This reverts commit 104eb98e62. (https://github.com/flutter/engine/pull/52680)
This commit is contained in:
Brandon DeRosier 2024-05-20 17:59:14 -07:00 committed by GitHub
parent a554688620
commit 2ffd763cfb
26 changed files with 33 additions and 1008 deletions

View File

@ -42255,8 +42255,6 @@ ORIGIN: ../../../flutter/impeller/aiks/aiks_context.cc + ../../../flutter/LICENS
ORIGIN: ../../../flutter/impeller/aiks/aiks_context.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/aiks/aiks_playground.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/aiks/aiks_playground.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/aiks/aiks_playground_inspector.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/aiks/aiks_playground_inspector.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/aiks/canvas.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/aiks/canvas.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/aiks/canvas_benchmarks.cc + ../../../flutter/LICENSE
@ -42354,8 +42352,6 @@ ORIGIN: ../../../flutter/impeller/core/allocator.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/core/allocator.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/core/buffer_view.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/core/buffer_view.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/core/capture.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/core/capture.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/core/device_buffer.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/core/device_buffer.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/core/device_buffer_descriptor.cc + ../../../flutter/LICENSE
@ -45126,8 +45122,6 @@ FILE: ../../../flutter/impeller/aiks/aiks_context.cc
FILE: ../../../flutter/impeller/aiks/aiks_context.h
FILE: ../../../flutter/impeller/aiks/aiks_playground.cc
FILE: ../../../flutter/impeller/aiks/aiks_playground.h
FILE: ../../../flutter/impeller/aiks/aiks_playground_inspector.cc
FILE: ../../../flutter/impeller/aiks/aiks_playground_inspector.h
FILE: ../../../flutter/impeller/aiks/canvas.cc
FILE: ../../../flutter/impeller/aiks/canvas.h
FILE: ../../../flutter/impeller/aiks/canvas_benchmarks.cc
@ -45225,8 +45219,6 @@ FILE: ../../../flutter/impeller/core/allocator.cc
FILE: ../../../flutter/impeller/core/allocator.h
FILE: ../../../flutter/impeller/core/buffer_view.cc
FILE: ../../../flutter/impeller/core/buffer_view.h
FILE: ../../../flutter/impeller/core/capture.cc
FILE: ../../../flutter/impeller/core/capture.h
FILE: ../../../flutter/impeller/core/device_buffer.cc
FILE: ../../../flutter/impeller/core/device_buffer.h
FILE: ../../../flutter/impeller/core/device_buffer_descriptor.cc

View File

@ -14,10 +14,6 @@ config("impeller_public_config") {
defines += [ "IMPELLER_DEBUG=1" ]
}
if (impeller_capture) {
defines += [ "IMPELLER_ENABLE_CAPTURE=1" ]
}
if (impeller_supports_rendering) {
defines += [ "IMPELLER_SUPPORTS_RENDERING=1" ]
}

View File

@ -45,8 +45,6 @@ impeller_component("aiks_playground") {
sources = [
"aiks_playground.cc",
"aiks_playground.h",
"aiks_playground_inspector.cc",
"aiks_playground_inspector.h",
]
deps = [
":aiks",

View File

@ -5,6 +5,7 @@
#include "impeller/aiks/aiks_playground.h"
#include <memory>
#include <optional>
#include "impeller/aiks/aiks_context.h"
#include "impeller/display_list/dl_dispatcher.h"
@ -24,14 +25,24 @@ void AiksPlayground::SetTypographerContext(
}
void AiksPlayground::TearDown() {
inspector_.HackResetDueToTextureLeaks();
PlaygroundTest::TearDown();
}
bool AiksPlayground::OpenPlaygroundHere(Picture picture) {
return OpenPlaygroundHere([&picture](AiksContext& renderer) -> Picture {
return std::move(picture);
});
if (!switches_.enable_playground) {
return true;
}
AiksContext renderer(GetContext(), typographer_context_);
if (!renderer.IsValid()) {
return false;
}
return Playground::OpenPlaygroundHere(
[&renderer, &picture](RenderTarget& render_target) -> bool {
return renderer.Render(picture, render_target, true);
});
}
bool AiksPlayground::OpenPlaygroundHere(AiksPlaygroundCallback callback) {
@ -46,10 +57,8 @@ bool AiksPlayground::OpenPlaygroundHere(AiksPlaygroundCallback callback) {
}
return Playground::OpenPlaygroundHere(
[this, &renderer, &callback](RenderTarget& render_target) -> bool {
const std::optional<Picture>& picture = inspector_.RenderInspector(
renderer, [&]() { return callback(renderer); });
[&renderer, &callback](RenderTarget& render_target) -> bool {
std::optional<Picture> picture = callback(renderer);
if (!picture.has_value()) {
return false;
}

View File

@ -7,7 +7,6 @@
#include "flutter/display_list/display_list.h"
#include "impeller/aiks/aiks_context.h"
#include "impeller/aiks/aiks_playground_inspector.h"
#include "impeller/aiks/picture.h"
#include "impeller/playground/playground_test.h"
#include "impeller/typographer/typographer_context.h"
@ -41,7 +40,6 @@ class AiksPlayground : public PlaygroundTest {
private:
std::shared_ptr<TypographerContext> typographer_context_;
AiksInspector inspector_;
AiksPlayground(const AiksPlayground&) = delete;

View File

@ -1,277 +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/aiks/aiks_playground_inspector.h"
#include <initializer_list>
#include "impeller/core/capture.h"
#include "impeller/entity/entity_pass.h"
#include "impeller/renderer/context.h"
#include "third_party/imgui/imgui.h"
#include "third_party/imgui/imgui_internal.h"
namespace impeller {
static const char* kElementsWindowName = "Elements";
static const char* kPropertiesWindowName = "Properties";
static const std::initializer_list<std::string> kSupportedDocuments = {
EntityPass::kCaptureDocumentName};
AiksInspector::AiksInspector() = default;
const std::optional<Picture>& AiksInspector::RenderInspector(
AiksContext& aiks_context,
const std::function<std::optional<Picture>()>& picture_callback) {
//----------------------------------------------------------------------------
/// Configure the next frame.
///
RenderCapture(aiks_context.GetContext()->capture);
//----------------------------------------------------------------------------
/// Configure the next frame.
///
if (ImGui::IsKeyPressed(ImGuiKey_Z)) {
wireframe_ = !wireframe_;
aiks_context.GetContentContext().SetWireframe(wireframe_);
}
if (ImGui::IsKeyPressed(ImGuiKey_C)) {
capturing_ = !capturing_;
if (capturing_) {
aiks_context.GetContext()->capture =
CaptureContext::MakeAllowlist({kSupportedDocuments});
}
}
if (!capturing_) {
hovered_element_ = nullptr;
selected_element_ = nullptr;
aiks_context.GetContext()->capture = CaptureContext::MakeInactive();
std::optional<Picture> new_picture = picture_callback();
// If the new picture doesn't have a pass, that means it was already moved
// into the inspector. Simply re-emit the last received valid picture.
if (!new_picture.has_value() || new_picture->pass) {
last_picture_ = std::move(new_picture);
}
}
return last_picture_;
}
void AiksInspector::HackResetDueToTextureLeaks() {
last_picture_.reset();
}
static const auto kPropertiesProcTable = CaptureProcTable{
.boolean =
[](CaptureBooleanProperty& p) {
ImGui::Checkbox(p.label.c_str(), &p.value);
},
.integer =
[](CaptureIntegerProperty& p) {
if (p.options.range.has_value()) {
ImGui::SliderInt(p.label.c_str(), &p.value,
static_cast<int>(p.options.range->min),
static_cast<int>(p.options.range->max));
return;
}
ImGui::InputInt(p.label.c_str(), &p.value);
},
.scalar =
[](CaptureScalarProperty& p) {
if (p.options.range.has_value()) {
ImGui::SliderFloat(p.label.c_str(), &p.value, p.options.range->min,
p.options.range->max);
return;
}
ImGui::DragFloat(p.label.c_str(), &p.value, 0.01);
},
.point =
[](CapturePointProperty& p) {
if (p.options.range.has_value()) {
ImGui::SliderFloat2(p.label.c_str(),
reinterpret_cast<float*>(&p.value),
p.options.range->min, p.options.range->max);
return;
}
ImGui::DragFloat2(p.label.c_str(), reinterpret_cast<float*>(&p.value),
0.01);
},
.vector3 =
[](CaptureVector3Property& p) {
if (p.options.range.has_value()) {
ImGui::SliderFloat3(p.label.c_str(),
reinterpret_cast<float*>(&p.value),
p.options.range->min, p.options.range->max);
return;
}
ImGui::DragFloat3(p.label.c_str(), reinterpret_cast<float*>(&p.value),
0.01);
},
.rect =
[](CaptureRectProperty& p) {
ImGui::DragFloat4(p.label.c_str(), reinterpret_cast<float*>(&p.value),
0.01);
},
.color =
[](CaptureColorProperty& p) {
ImGui::ColorEdit4(p.label.c_str(),
reinterpret_cast<float*>(&p.value));
},
.matrix =
[](CaptureMatrixProperty& p) {
float* pointer = reinterpret_cast<float*>(&p.value);
ImGui::DragFloat4((p.label + " X basis").c_str(), pointer, 0.001);
ImGui::DragFloat4((p.label + " Y basis").c_str(), pointer + 4, 0.001);
ImGui::DragFloat4((p.label + " Z basis").c_str(), pointer + 8, 0.001);
ImGui::DragFloat4((p.label + " Translation").c_str(), pointer + 12,
0.001);
},
.string =
[](CaptureStringProperty& p) {
ImGui::InputTextEx(p.label.c_str(), "",
// Fine as long as it's read-only.
const_cast<char*>(p.value.c_str()), p.value.size(),
ImVec2(0, 0), ImGuiInputTextFlags_ReadOnly);
},
};
void AiksInspector::RenderCapture(CaptureContext& capture_context) {
if (!capturing_) {
return;
}
auto document = capture_context.GetDocument(EntityPass::kCaptureDocumentName);
//----------------------------------------------------------------------------
/// Setup a shared dockspace to collect the capture windows.
///
ImGui::SetNextWindowBgAlpha(0.5);
ImGui::Begin("Capture");
auto dockspace_id = ImGui::GetID("CaptureDockspace");
if (!ImGui::DockBuilderGetNode(dockspace_id)) {
ImGui::SetWindowSize(ImVec2(370, 680));
ImGui::SetWindowPos(ImVec2(640, 55));
ImGui::DockBuilderRemoveNode(dockspace_id);
ImGui::DockBuilderAddNode(dockspace_id);
ImGuiID opposite_id;
ImGuiID up_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Up, 0.6,
nullptr, &opposite_id);
ImGuiID down_id = ImGui::DockBuilderSplitNode(opposite_id, ImGuiDir_Down,
0.0, nullptr, nullptr);
ImGui::DockBuilderDockWindow(kElementsWindowName, up_id);
ImGui::DockBuilderDockWindow(kPropertiesWindowName, down_id);
ImGui::DockBuilderFinish(dockspace_id);
}
ImGui::DockSpace(dockspace_id);
ImGui::End(); // Capture window.
//----------------------------------------------------------------------------
/// Element hierarchy window.
///
ImGui::Begin(kElementsWindowName);
auto root_element = document.GetElement();
hovered_element_ = nullptr;
if (root_element) {
RenderCaptureElement(*root_element);
}
ImGui::End(); // Hierarchy window.
if (selected_element_) {
//----------------------------------------------------------------------------
/// Properties window.
///
ImGui::Begin(kPropertiesWindowName);
{
selected_element_->properties.Iterate([&](CaptureProperty& property) {
property.Invoke(kPropertiesProcTable);
});
}
ImGui::End(); // Inspector window.
//----------------------------------------------------------------------------
/// Selected coverage highlighting.
///
auto coverage_property =
selected_element_->properties.FindFirstByLabel("Coverage");
if (coverage_property) {
auto coverage = coverage_property->AsRect();
if (coverage.has_value()) {
Scalar scale = ImGui::GetWindowDpiScale();
ImGui::GetBackgroundDrawList()->AddRect(
ImVec2(coverage->GetLeft() / scale,
coverage->GetTop() / scale), // p_min
ImVec2(coverage->GetRight() / scale,
coverage->GetBottom() / scale), // p_max
0x992222FF, // col
0.0, // rounding
ImDrawFlags_None, // flags
8.0); // thickness
}
}
}
//----------------------------------------------------------------------------
/// Hover coverage highlight.
///
if (hovered_element_) {
auto coverage_property =
hovered_element_->properties.FindFirstByLabel("Coverage");
if (coverage_property) {
auto coverage = coverage_property->AsRect();
if (coverage.has_value()) {
Scalar scale = ImGui::GetWindowDpiScale();
ImGui::GetBackgroundDrawList()->AddRect(
ImVec2(coverage->GetLeft() / scale,
coverage->GetTop() / scale), // p_min
ImVec2(coverage->GetRight() / scale,
coverage->GetBottom() / scale), // p_max
0x66FF2222, // col
0.0, // rounding
ImDrawFlags_None, // flags
8.0); // thickness
}
}
}
}
void AiksInspector::RenderCaptureElement(CaptureElement& element) {
ImGui::PushID(&element);
bool is_selected = selected_element_ == &element;
bool has_children = element.children.Count() > 0;
bool opened = ImGui::TreeNodeEx(
element.label.c_str(), (is_selected ? ImGuiTreeNodeFlags_Selected : 0) |
(has_children ? 0 : ImGuiTreeNodeFlags_Leaf) |
ImGuiTreeNodeFlags_SpanFullWidth |
ImGuiTreeNodeFlags_OpenOnArrow |
ImGuiTreeNodeFlags_DefaultOpen);
if (ImGui::IsItemClicked()) {
selected_element_ = &element;
}
if (ImGui::IsItemHovered()) {
hovered_element_ = &element;
}
if (opened) {
element.children.Iterate(
[&](CaptureElement& child) { RenderCaptureElement(child); });
ImGui::TreePop();
}
ImGui::PopID();
}
} // namespace impeller

View File

@ -1,55 +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_AIKS_AIKS_PLAYGROUND_INSPECTOR_H_
#define FLUTTER_IMPELLER_AIKS_AIKS_PLAYGROUND_INSPECTOR_H_
#include <functional>
#include <optional>
#include "flutter/fml/macros.h"
#include "impeller/aiks/aiks_context.h"
#include "impeller/aiks/picture.h"
#include "impeller/core/capture.h"
#include "impeller/renderer/context.h"
namespace impeller {
class AiksInspector {
public:
AiksInspector();
const std::optional<Picture>& RenderInspector(
AiksContext& aiks_context,
const std::function<std::optional<Picture>()>& picture_callback);
// Resets (releases) the underlying |Picture| object.
//
// Underlying issue: <https://github.com/flutter/flutter/issues/134678>.
//
// The tear-down code is not running in the right order; we still have a
// reference to the |Picture| object when the |Context| is being destroyed,
// which causes the |Texture| objects to leak.
//
// TODO(matanlurey): https://github.com/flutter/flutter/issues/134748.
void HackResetDueToTextureLeaks();
private:
void RenderCapture(CaptureContext& capture_context);
void RenderCaptureElement(CaptureElement& element);
bool capturing_ = false;
bool wireframe_ = false;
CaptureElement* hovered_element_ = nullptr;
CaptureElement* selected_element_ = nullptr;
std::optional<Picture> last_picture_;
AiksInspector(const AiksInspector&) = delete;
AiksInspector& operator=(const AiksInspector&) = delete;
};
}; // namespace impeller
#endif // FLUTTER_IMPELLER_AIKS_AIKS_PLAYGROUND_INSPECTOR_H_

View File

@ -20,7 +20,6 @@
#include "impeller/aiks/image_filter.h"
#include "impeller/aiks/paint_pass_delegate.h"
#include "impeller/aiks/testing/context_spy.h"
#include "impeller/core/capture.h"
#include "impeller/core/device_buffer.h"
#include "impeller/entity/contents/solid_color_contents.h"
#include "impeller/geometry/color.h"
@ -2596,38 +2595,6 @@ TEST_P(AiksTest, PipelineBlendSingleParameter) {
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
TEST_P(AiksTest, CaptureContext) {
auto capture_context = CaptureContext::MakeAllowlist({"TestDocument"});
auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
Canvas canvas;
capture_context.Rewind();
auto document = capture_context.GetDocument("TestDocument");
auto color = document.AddColor("Background color", Color::CornflowerBlue());
canvas.DrawPaint({.color = color});
if (AiksTest::ImGuiBegin("TestDocument", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
document.GetElement()->properties.Iterate([](CaptureProperty& property) {
property.Invoke({.color = [](CaptureColorProperty& p) {
ImGui::ColorEdit4(p.label.c_str(),
reinterpret_cast<float*>(&p.value));
}});
});
ImGui::End();
}
return canvas.EndRecordingAsPicture();
};
OpenPlaygroundHere(callback);
}
TEST_P(AiksTest, CaptureInactivatedByDefault) {
ASSERT_FALSE(GetContext()->capture.IsActive());
}
// Regression test for https://github.com/flutter/flutter/issues/134678.
TEST_P(AiksTest, ReleasesTextureOnTeardown) {
auto context = MakeContext();

View File

@ -10,8 +10,6 @@ impeller_component("core") {
"allocator.h",
"buffer_view.cc",
"buffer_view.h",
"capture.cc",
"capture.h",
"device_buffer.cc",
"device_buffer.h",
"device_buffer_descriptor.cc",

View File

@ -1,220 +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/core/capture.h"
#include <initializer_list>
#include <memory>
namespace impeller {
//-----------------------------------------------------------------------------
/// CaptureProperty
///
CaptureProperty::CaptureProperty(const std::string& label, Options options)
: CaptureCursorListElement(label), options(options) {}
CaptureProperty::~CaptureProperty() = default;
bool CaptureProperty::MatchesCloselyEnough(const CaptureProperty& other) const {
if (label != other.label) {
return false;
}
if (GetType() != other.GetType()) {
return false;
}
return true;
}
#define _CAPTURE_PROPERTY_CAST_DEFINITION(type_name, pascal_name, lower_name) \
std::optional<type_name> CaptureProperty::As##pascal_name() const { \
if (GetType() != Type::k##pascal_name) { \
return std::nullopt; \
} \
return reinterpret_cast<const Capture##pascal_name##Property*>(this) \
->value; \
}
_FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_CAST_DEFINITION);
#define _CAPTURE_PROPERTY_DEFINITION(type_name, pascal_name, lower_name) \
Capture##pascal_name##Property::Capture##pascal_name##Property( \
const std::string& label, type_name value, Options options) \
: CaptureProperty(label, options), value(std::move(value)) {} \
\
std::shared_ptr<Capture##pascal_name##Property> \
Capture##pascal_name##Property::Make(const std::string& label, \
type_name value, Options options) { \
auto result = std::shared_ptr<Capture##pascal_name##Property>( \
new Capture##pascal_name##Property(label, std::move(value), options)); \
return result; \
} \
\
CaptureProperty::Type Capture##pascal_name##Property::GetType() const { \
return Type::k##pascal_name; \
} \
\
void Capture##pascal_name##Property::Invoke( \
const CaptureProcTable& proc_table) { \
proc_table.lower_name(*this); \
}
_FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_DEFINITION);
//-----------------------------------------------------------------------------
/// CaptureElement
///
CaptureElement::CaptureElement(const std::string& label)
: CaptureCursorListElement(label) {}
std::shared_ptr<CaptureElement> CaptureElement::Make(const std::string& label) {
return std::shared_ptr<CaptureElement>(new CaptureElement(label));
}
void CaptureElement::Rewind() {
properties.Rewind();
children.Rewind();
}
bool CaptureElement::MatchesCloselyEnough(const CaptureElement& other) const {
return label == other.label;
}
//-----------------------------------------------------------------------------
/// Capture
///
Capture::Capture() = default;
#ifdef IMPELLER_ENABLE_CAPTURE
Capture::Capture(const std::string& label)
: element_(CaptureElement::Make(label)), active_(true) {
element_->label = label;
}
#else
Capture::Capture(const std::string& label) {}
#endif
Capture Capture::MakeInactive() {
return Capture();
}
std::shared_ptr<CaptureElement> Capture::GetElement() const {
#ifdef IMPELLER_ENABLE_CAPTURE
return element_;
#else
return nullptr;
#endif
}
void Capture::Rewind() {
return GetElement()->Rewind();
}
#ifdef IMPELLER_ENABLE_CAPTURE
#define _CAPTURE_PROPERTY_RECORDER_DEFINITION(type_name, pascal_name, \
lower_name) \
type_name Capture::Add##pascal_name(std::string_view label, type_name value, \
CaptureProperty::Options options) { \
if (!active_) { \
return value; \
} \
FML_DCHECK(element_ != nullptr); \
\
std::string label_clone = std::string(label); \
auto new_value = Capture##pascal_name##Property::Make( \
label_clone, std::move(value), options); \
\
auto next = std::reinterpret_pointer_cast<Capture##pascal_name##Property>( \
element_->properties.GetNext(std::move(new_value), options.readonly)); \
\
return next->value; \
}
_FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_RECORDER_DEFINITION);
#endif
//-----------------------------------------------------------------------------
/// CaptureContext
///
#ifdef IMPELLER_ENABLE_CAPTURE
CaptureContext::CaptureContext() : active_(true) {}
CaptureContext::CaptureContext(std::initializer_list<std::string> allowlist)
: active_(true), allowlist_(allowlist) {}
#else
CaptureContext::CaptureContext() {}
CaptureContext::CaptureContext(std::initializer_list<std::string> allowlist) {}
#endif
CaptureContext::CaptureContext(CaptureContext::InactiveFlag) {}
CaptureContext CaptureContext::MakeInactive() {
return CaptureContext(InactiveFlag{});
}
CaptureContext CaptureContext::MakeAllowlist(
std::initializer_list<std::string> allowlist) {
return CaptureContext(allowlist);
}
bool CaptureContext::IsActive() const {
#ifdef IMPELLER_ENABLE_CAPTURE
return active_;
#else
return false;
#endif
}
void CaptureContext::Rewind() {
#ifdef IMPELLER_ENABLE_CAPTURE
for (auto& [name, capture] : documents_) {
capture.GetElement()->Rewind();
}
#else
return;
#endif
}
Capture CaptureContext::GetDocument(const std::string& label) {
#ifdef IMPELLER_ENABLE_CAPTURE
if (!active_) {
return Capture::MakeInactive();
}
if (allowlist_.has_value()) {
if (allowlist_->find(label) == allowlist_->end()) {
return Capture::MakeInactive();
}
}
auto found = documents_.find(label);
if (found != documents_.end()) {
// Always rewind when fetching an existing document.
found->second.Rewind();
return found->second;
}
auto new_document = Capture(label);
documents_.emplace(label, new_document);
return new_document;
#else
return Capture::MakeInactive();
#endif
}
bool CaptureContext::DoesDocumentExist(const std::string& label) const {
#ifdef IMPELLER_ENABLE_CAPTURE
if (!active_) {
return false;
}
return documents_.find(label) != documents_.end();
#else
return false;
#endif
}
} // namespace impeller

View File

@ -1,300 +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_CORE_CAPTURE_H_
#define FLUTTER_IMPELLER_CORE_CAPTURE_H_
#include <functional>
#include <initializer_list>
#include <memory>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "flutter/fml/logging.h"
#include "flutter/fml/macros.h"
#include "impeller/geometry/color.h"
#include "impeller/geometry/matrix.h"
#include "impeller/geometry/point.h"
#include "impeller/geometry/rect.h"
#include "impeller/geometry/scalar.h"
#include "impeller/geometry/vector.h"
namespace impeller {
struct CaptureProcTable;
#define _FOR_EACH_CAPTURE_PROPERTY(PROPERTY_V) \
PROPERTY_V(bool, Boolean, boolean) \
PROPERTY_V(int, Integer, integer) \
PROPERTY_V(Scalar, Scalar, scalar) \
PROPERTY_V(Point, Point, point) \
PROPERTY_V(Vector3, Vector3, vector3) \
PROPERTY_V(Rect, Rect, rect) \
PROPERTY_V(Color, Color, color) \
PROPERTY_V(Matrix, Matrix, matrix) \
PROPERTY_V(std::string, String, string)
template <typename Type>
struct CaptureCursorListElement {
std::string label;
explicit CaptureCursorListElement(const std::string& label) : label(label){};
virtual ~CaptureCursorListElement() = default;
//----------------------------------------------------------------------------
/// @brief Determines if previously captured data matches closely enough with
/// newly recorded data to safely emitted in its place. If this
/// returns `false`, then the remaining elements in the capture list
/// are discarded and re-recorded.
///
/// This mechanism ensures that the UI of an interactive inspector can
/// never deviate from reality, even if the schema of the captured
/// data were to significantly deviate.
///
virtual bool MatchesCloselyEnough(const Type& other) const = 0;
};
#define _CAPTURE_TYPE(type_name, pascal_name, lower_name) k##pascal_name,
#define _CAPTURE_PROPERTY_CAST_DECLARATION(type_name, pascal_name, lower_name) \
std::optional<type_name> As##pascal_name() const;
/// A capturable property type
struct CaptureProperty : public CaptureCursorListElement<CaptureProperty> {
enum class Type { _FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_TYPE) };
struct Options {
struct Range {
Scalar min;
Scalar max;
};
/// Readonly properties are always re-recorded during capture. Any edits
/// made to readonly values in-between captures are overwritten during the
/// next capture.
bool readonly = false;
/// An inspector hint that can be used for displaying sliders. Only used for
/// numeric types. Rounded down for integer types.
std::optional<Range> range;
};
Options options;
CaptureProperty(const std::string& label, Options options);
virtual ~CaptureProperty();
virtual Type GetType() const = 0;
virtual void Invoke(const CaptureProcTable& proc_table) = 0;
bool MatchesCloselyEnough(const CaptureProperty& other) const override;
_FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_CAST_DECLARATION)
};
#define _CAPTURE_PROPERTY_DECLARATION(type_name, pascal_name, lower_name) \
struct Capture##pascal_name##Property final : public CaptureProperty { \
type_name value; \
\
static std::shared_ptr<Capture##pascal_name##Property> \
Make(const std::string& label, type_name value, Options options); \
\
/* |CaptureProperty| */ \
Type GetType() const override; \
\
/* |CaptureProperty| */ \
void Invoke(const CaptureProcTable& proc_table) override; \
\
private: \
Capture##pascal_name##Property(const std::string& label, \
type_name value, \
Options options); \
\
FML_DISALLOW_COPY_AND_ASSIGN(Capture##pascal_name##Property); \
};
_FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_DECLARATION);
#define _CAPTURE_PROC(type_name, pascal_name, lower_name) \
std::function<void(Capture##pascal_name##Property&)> lower_name = \
[](Capture##pascal_name##Property& value) {};
struct CaptureProcTable {
_FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROC)
};
template <typename Type>
class CapturePlaybackList {
public:
CapturePlaybackList() = default;
~CapturePlaybackList() {
// Force the list element type to inherit the CRTP type. We can't enforce
// this as a template requirement directly because `CaptureElement` has a
// recursive `CaptureCursorList<CaptureElement>` property, and so the
// compiler fails the check due to the type being incomplete.
static_assert(std::is_base_of_v<CaptureCursorListElement<Type>, Type>);
}
void Rewind() { cursor_ = 0; }
size_t Count() { return values_.size(); }
std::shared_ptr<Type> GetNext(std::shared_ptr<Type> captured,
bool force_overwrite) {
if (cursor_ < values_.size()) {
std::shared_ptr<Type>& result = values_[cursor_];
if (result->MatchesCloselyEnough(*captured)) {
if (force_overwrite) {
values_[cursor_] = captured;
}
// Safe playback is possible.
++cursor_;
return result;
}
// The data has changed too much from the last capture to safely continue
// playback. Discard this and all subsequent elements to re-record.
values_.resize(cursor_);
}
++cursor_;
values_.push_back(captured);
return captured;
}
std::shared_ptr<Type> FindFirstByLabel(const std::string& label) {
for (std::shared_ptr<Type>& value : values_) {
if (value->label == label) {
return value;
}
}
return nullptr;
}
void Iterate(std::function<void(Type&)> iterator) const {
for (auto& value : values_) {
iterator(*value);
}
}
private:
size_t cursor_ = 0;
std::vector<std::shared_ptr<Type>> values_;
CapturePlaybackList(const CapturePlaybackList&) = delete;
CapturePlaybackList& operator=(const CapturePlaybackList&) = delete;
};
/// A document of capture data, containing a list of properties and a list
/// of subdocuments.
struct CaptureElement final : public CaptureCursorListElement<CaptureElement> {
CapturePlaybackList<CaptureProperty> properties;
CapturePlaybackList<CaptureElement> children;
static std::shared_ptr<CaptureElement> Make(const std::string& label);
void Rewind();
bool MatchesCloselyEnough(const CaptureElement& other) const override;
private:
explicit CaptureElement(const std::string& label);
CaptureElement(const CaptureElement&) = delete;
CaptureElement& operator=(const CaptureElement&) = delete;
};
#ifdef IMPELLER_ENABLE_CAPTURE
#define _CAPTURE_PROPERTY_RECORDER_DECLARATION(type_name, pascal_name, \
lower_name) \
type_name Add##pascal_name(std::string_view label, type_name value, \
CaptureProperty::Options options = {});
#else
#define _CAPTURE_PROPERTY_RECORDER_DECLARATION(type_name, pascal_name, \
lower_name) \
inline type_name Add##pascal_name(std::string_view label, type_name value, \
CaptureProperty::Options options = {}) { \
return value; \
}
#endif
class Capture {
public:
explicit Capture(const std::string& label);
Capture();
static Capture MakeInactive();
inline Capture CreateChild(std::string_view label) {
#ifdef IMPELLER_ENABLE_CAPTURE
if (!active_) {
return Capture();
}
std::string label_copy = std::string(label);
auto new_capture = Capture(label_copy);
new_capture.element_ =
element_->children.GetNext(new_capture.element_, false);
new_capture.element_->Rewind();
return new_capture;
#else
return Capture();
#endif
}
std::shared_ptr<CaptureElement> GetElement() const;
void Rewind();
_FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_RECORDER_DECLARATION)
private:
#ifdef IMPELLER_ENABLE_CAPTURE
std::shared_ptr<CaptureElement> element_;
bool active_ = false;
#endif
};
class CaptureContext {
public:
CaptureContext();
static CaptureContext MakeInactive();
static CaptureContext MakeAllowlist(
std::initializer_list<std::string> allowlist);
bool IsActive() const;
void Rewind();
Capture GetDocument(const std::string& label);
bool DoesDocumentExist(const std::string& label) const;
private:
struct InactiveFlag {};
explicit CaptureContext(InactiveFlag);
CaptureContext(std::initializer_list<std::string> allowlist);
#ifdef IMPELLER_ENABLE_CAPTURE
bool active_ = false;
std::optional<std::unordered_set<std::string>> allowlist_;
std::unordered_map<std::string, Capture> documents_;
#endif
};
} // namespace impeller
#endif // FLUTTER_IMPELLER_CORE_CAPTURE_H_

View File

@ -10,18 +10,17 @@
#include <optional>
#include <unordered_map>
#include "flutter/fml/build_config.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/status_or.h"
#include "impeller/base/validation.h"
#include "impeller/core/formats.h"
#include "impeller/core/host_buffer.h"
#include "impeller/entity/entity.h"
#include "impeller/renderer/capabilities.h"
#include "impeller/renderer/command_buffer.h"
#include "impeller/renderer/pipeline.h"
#include "impeller/renderer/pipeline_descriptor.h"
#include "impeller/renderer/render_target.h"
#include "impeller/typographer/lazy_glyph_atlas.h"
#include "impeller/typographer/typographer_context.h"
#include "impeller/entity/border_mask_blur.frag.h"
@ -54,8 +53,6 @@
#include "impeller/entity/tiled_texture_fill.frag.h"
#include "impeller/entity/yuv_to_rgb_filter.frag.h"
#include "impeller/typographer/glyph_atlas.h"
#include "impeller/entity/conical_gradient_ssbo_fill.frag.h"
#include "impeller/entity/linear_gradient_ssbo_fill.frag.h"
#include "impeller/entity/radial_gradient_ssbo_fill.frag.h"

View File

@ -6,12 +6,11 @@
#include <optional>
#include "fml/logging.h"
#include "impeller/base/strings.h"
#include "impeller/base/validation.h"
#include "impeller/core/formats.h"
#include "impeller/entity/contents/anonymous_contents.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/contents/texture_contents.h"
#include "impeller/entity/entity.h"
#include "impeller/renderer/command_buffer.h"
#include "impeller/renderer/render_pass.h"

View File

@ -48,11 +48,10 @@ std::optional<Rect> SolidColorContents::GetCoverage(
bool SolidColorContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
auto capture = entity.GetCapture().CreateChild("SolidColorContents");
using VS = SolidFillPipeline::VertexShader;
VS::FrameInfo frame_info;
frame_info.color = capture.AddColor("Color", GetColor()).Premultiply();
frame_info.color = GetColor().Premultiply();
PipelineBuilderCallback pipeline_callback =
[&renderer](ContentContextOptions options) {

View File

@ -109,8 +109,6 @@ std::optional<Snapshot> TextureContents::RenderToSnapshot(
bool TextureContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
auto capture = entity.GetCapture().CreateChild("TextureContents");
using VS = TextureFillVertexShader;
using FS = TextureFillFragmentShader;
using FSStrict = TextureFillStrictSrcFragmentShader;
@ -124,18 +122,15 @@ bool TextureContents::Render(const ContentContext& renderer,
texture_->GetTextureDescriptor().type == TextureType::kTextureExternalOES;
FML_DCHECK(!is_external_texture);
auto source_rect = capture.AddRect("Source rect", source_rect_);
auto texture_coords =
Rect::MakeSize(texture_->GetSize()).Project(source_rect);
Rect::MakeSize(texture_->GetSize()).Project(source_rect_);
VertexBufferBuilder<VS::PerVertexData> vertex_builder;
auto destination_rect =
capture.AddRect("Destination rect", destination_rect_);
vertex_builder.AddVertices({
{destination_rect.GetLeftTop(), texture_coords.GetLeftTop()},
{destination_rect.GetRightTop(), texture_coords.GetRightTop()},
{destination_rect.GetLeftBottom(), texture_coords.GetLeftBottom()},
{destination_rect.GetRightBottom(), texture_coords.GetRightBottom()},
{destination_rect_.GetLeftTop(), texture_coords.GetLeftTop()},
{destination_rect_.GetRightTop(), texture_coords.GetRightTop()},
{destination_rect_.GetLeftBottom(), texture_coords.GetLeftBottom()},
{destination_rect_.GetRightBottom(), texture_coords.GetRightBottom()},
});
auto& host_buffer = renderer.GetTransientsBuffer();
@ -170,11 +165,11 @@ bool TextureContents::Render(const ContentContext& renderer,
// texel to ensure that linear filtering does not sample anything outside
// the source rect bounds.
auto strict_texture_coords =
Rect::MakeSize(texture_->GetSize()).Project(source_rect.Expand(-0.5));
Rect::MakeSize(texture_->GetSize()).Project(source_rect_.Expand(-0.5));
FSStrict::FragInfo frag_info;
frag_info.source_rect = Vector4(strict_texture_coords.GetLTRB());
frag_info.alpha = capture.AddScalar("Alpha", GetOpacity());
frag_info.alpha = GetOpacity();
FSStrict::BindFragInfo(pass, host_buffer.EmplaceUniform((frag_info)));
FSStrict::BindTextureSampler(
pass, texture_,
@ -182,7 +177,7 @@ bool TextureContents::Render(const ContentContext& renderer,
sampler_descriptor_));
} else {
FS::FragInfo frag_info;
frag_info.alpha = capture.AddScalar("Alpha", GetOpacity());
frag_info.alpha = GetOpacity();
FS::BindFragInfo(pass, host_buffer.EmplaceUniform((frag_info)));
FS::BindTextureSampler(
pass, texture_,

View File

@ -188,16 +188,8 @@ Scalar Entity::DeriveTextScale() const {
return GetTransform().GetMaxBasisLengthXY();
}
Capture& Entity::GetCapture() const {
return capture_;
}
Entity Entity::Clone() const {
return Entity(*this);
}
void Entity::SetCapture(Capture capture) const {
capture_ = std::move(capture);
}
} // namespace impeller

View File

@ -7,7 +7,6 @@
#include <cstdint>
#include "impeller/core/capture.h"
#include "impeller/entity/contents/contents.h"
#include "impeller/geometry/color.h"
#include "impeller/geometry/matrix.h"
@ -123,10 +122,6 @@ class Entity {
Scalar DeriveTextScale() const;
Capture& GetCapture() const;
void SetCapture(Capture capture) const;
Entity Clone() const;
private:
@ -136,7 +131,6 @@ class Entity {
std::shared_ptr<Contents> contents_;
BlendMode blend_mode_ = BlendMode::kSourceOver;
uint32_t clip_depth_ = 1u;
mutable Capture capture_;
};
} // namespace impeller

View File

@ -44,8 +44,6 @@ std::tuple<std::optional<Color>, BlendMode> ElementAsBackgroundColor(
}
} // namespace
const std::string EntityPass::kCaptureDocumentName = "EntityPass";
EntityPass::EntityPass() = default;
EntityPass::~EntityPass() = default;
@ -354,9 +352,6 @@ bool EntityPass::DoesBackdropGetRead(ContentContext& renderer) const {
bool EntityPass::Render(ContentContext& renderer,
const RenderTarget& render_target) const {
auto capture =
renderer.GetContext()->capture.GetDocument(kCaptureDocumentName);
renderer.GetRenderTargetCache()->Start();
fml::ScopedCleanupClosure reset_state([&renderer]() {
renderer.GetLazyGlyphAtlas()->ResetTextFrames();
@ -377,10 +372,6 @@ bool EntityPass::Render(ContentContext& renderer,
return false;
}
capture.AddRect("Coverage",
Rect::MakeSize(root_render_target.GetRenderTargetSize()),
{.readonly = true});
const auto& lazy_glyph_atlas = renderer.GetLazyGlyphAtlas();
IterateAllEntities([&lazy_glyph_atlas](const Entity& entity) {
if (const auto& contents = entity.GetContents()) {
@ -402,7 +393,6 @@ bool EntityPass::Render(ContentContext& renderer,
GetClearColorOrDefault(render_target.GetRenderTargetSize()));
if (!OnRender(renderer, // renderer
capture, // capture
offscreen_target.GetRenderTarget()
.GetRenderTargetSize(), // root_pass_size
offscreen_target, // pass_target
@ -509,7 +499,6 @@ bool EntityPass::Render(ContentContext& renderer,
return OnRender( //
renderer, // renderer
capture, // capture
root_render_target.GetRenderTargetSize(), // root_pass_size
pass_target, // pass_target
Point(), // global_pass_position
@ -521,7 +510,6 @@ bool EntityPass::Render(ContentContext& renderer,
EntityPass::EntityResult EntityPass::GetEntityForElement(
const EntityPass::Element& element,
ContentContext& renderer,
Capture& capture,
InlinePassContext& pass_context,
ISize root_pass_size,
Point global_pass_position,
@ -533,7 +521,6 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
///
if (const auto& entity = std::get_if<Entity>(&element)) {
Entity element_entity = entity->Clone();
element_entity.SetCapture(capture.CreateChild("Entity"));
if (!global_pass_position.IsZero()) {
// If the pass image is going to be rendered with a non-zero position,
@ -558,11 +545,9 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
if (!subpass->backdrop_filter_proc_ &&
subpass->delegate_->CanCollapseIntoParentPass(subpass)) {
auto subpass_capture = capture.CreateChild("EntityPass (Collapsed)");
// Directly render into the parent target and move on.
if (!subpass->OnRender(
renderer, // renderer
subpass_capture, // capture
root_pass_size, // root_pass_size
pass_context.GetPassTarget(), // pass_target
global_pass_position, // global_pass_position
@ -606,12 +591,10 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
if (!clip_coverage_stack.HasCoverage()) {
// The current clip is empty. This means the pass texture won't be
// visible, so skip it.
capture.CreateChild("Subpass Entity (Skipped: Empty clip A)");
return EntityPass::EntityResult::Skip();
}
auto clip_coverage_back = clip_coverage_stack.CurrentClipCoverage();
if (!clip_coverage_back.has_value()) {
capture.CreateChild("Subpass Entity (Skipped: Empty clip B)");
return EntityPass::EntityResult::Skip();
}
@ -623,14 +606,12 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
.GetRenderTargetSize()))
.Intersection(clip_coverage_back.value());
if (!coverage_limit.has_value()) {
capture.CreateChild("Subpass Entity (Skipped: Empty coverage limit A)");
return EntityPass::EntityResult::Skip();
}
coverage_limit =
coverage_limit->Intersection(Rect::MakeSize(root_pass_size));
if (!coverage_limit.has_value()) {
capture.CreateChild("Subpass Entity (Skipped: Empty coverage limit B)");
return EntityPass::EntityResult::Skip();
}
@ -639,13 +620,11 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
? coverage_limit
: GetSubpassCoverage(*subpass, coverage_limit);
if (!subpass_coverage.has_value()) {
capture.CreateChild("Subpass Entity (Skipped: Empty subpass coverage A)");
return EntityPass::EntityResult::Skip();
}
auto subpass_size = ISize(subpass_coverage->GetSize());
if (subpass_size.IsEmpty()) {
capture.CreateChild("Subpass Entity (Skipped: Empty subpass coverage B)");
return EntityPass::EntityResult::Skip();
}
@ -660,9 +639,6 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
return EntityPass::EntityResult::Failure();
}
auto subpass_capture = capture.CreateChild("EntityPass");
subpass_capture.AddRect("Coverage", *subpass_coverage, {.readonly = true});
// Start non-collapsed subpasses with a fresh clip coverage stack limited by
// the subpass coverage. This is important because image filters applied to
// save layers may transform the subpass texture after it's rendered,
@ -674,7 +650,6 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
// time they are transient).
if (!subpass->OnRender(
renderer, // renderer
subpass_capture, // capture
root_pass_size, // root_pass_size
subpass_target, // pass_target
subpass_coverage->GetOrigin(), // global_pass_position
@ -714,16 +689,11 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
return EntityPass::EntityResult::Failure();
}
Entity element_entity;
Capture subpass_texture_capture =
capture.CreateChild("Entity (Subpass texture)");
element_entity.SetClipDepth(subpass->clip_depth_);
element_entity.SetCapture(subpass_texture_capture);
element_entity.SetContents(std::move(offscreen_texture_contents));
element_entity.SetBlendMode(subpass->blend_mode_);
element_entity.SetTransform(subpass_texture_capture.AddMatrix(
"Transform",
Matrix::MakeTranslation(
Vector3(subpass_coverage->GetOrigin() - global_pass_position))));
element_entity.SetTransform(Matrix::MakeTranslation(
Vector3(subpass_coverage->GetOrigin() - global_pass_position)));
return EntityPass::EntityResult::Success(std::move(element_entity));
}
@ -846,7 +816,6 @@ bool EntityPass::RenderElement(Entity& element_entity,
bool EntityPass::OnRender(
ContentContext& renderer,
Capture& capture,
ISize root_pass_size,
EntityPassTarget& pass_target,
Point global_pass_position,
@ -919,7 +888,6 @@ bool EntityPass::OnRender(
EntityResult result =
GetEntityForElement(element, // element
renderer, // renderer
capture, // capture
pass_context, // pass_context
root_pass_size, // root_pass_size
global_pass_position, // global_pass_position

View File

@ -53,8 +53,6 @@ class EntityPass {
/// `GetEntityForElement()`.
using Element = std::variant<Entity, std::unique_ptr<EntityPass>>;
static const std::string kCaptureDocumentName;
using BackdropFilterProc = std::function<std::shared_ptr<FilterContents>(
FilterInput::Ref,
const Matrix& effect_transform,
@ -238,7 +236,6 @@ class EntityPass {
EntityResult GetEntityForElement(const EntityPass::Element& element,
ContentContext& renderer,
Capture& capture,
InlinePassContext& pass_context,
ISize root_pass_size,
Point global_pass_position,
@ -304,7 +301,6 @@ class EntityPass {
/// parent pass.
///
bool OnRender(ContentContext& renderer,
Capture& capture,
ISize root_pass_size,
EntityPassTarget& pass_target,
Point global_pass_position,

View File

@ -124,18 +124,6 @@ EntityPassClipStack::ClipStateResult EntityPassClipStack::ApplyClipState(
} break;
}
#ifdef IMPELLER_ENABLE_CAPTURE
{
auto element_entity_coverage = entity.GetCoverage();
if (element_entity_coverage.has_value()) {
element_entity_coverage =
element_entity_coverage->Shift(global_pass_position);
entity.GetCapture().AddRect("Coverage", *element_entity_coverage,
{.readonly = true});
}
}
#endif
RecordEntity(entity, global_clip_coverage.type,
subpass_state.clip_coverage.back().coverage);

View File

@ -4,13 +4,11 @@
#include "impeller/renderer/context.h"
#include "impeller/core/capture.h"
namespace impeller {
Context::~Context() = default;
Context::Context() : capture(CaptureContext::MakeInactive()) {}
Context::Context() = default;
bool Context::UpdateOffscreenLayerPixelFormat(PixelFormat format) {
return false;

View File

@ -9,7 +9,6 @@
#include <string>
#include "impeller/core/allocator.h"
#include "impeller/core/capture.h"
#include "impeller/core/formats.h"
#include "impeller/renderer/capabilities.h"
#include "impeller/renderer/command_queue.h"
@ -171,8 +170,6 @@ class Context {
///
virtual void Shutdown() = 0;
CaptureContext capture;
/// Stores a task on the `ContextMTL` that is awaiting access for the GPU.
///
/// The task will be executed in the event that the GPU access has changed to

View File

@ -11,9 +11,6 @@ declare_args() {
impeller_debug =
flutter_runtime_mode == "debug" || flutter_runtime_mode == "profile"
# Whether the runtime capture/playback system is enabled.
impeller_capture = flutter_runtime_mode == "debug"
# Whether the Metal backend is enabled.
impeller_enable_metal = (is_mac || is_ios) && target_os != "fuchsia"

View File

@ -12,6 +12,7 @@
#include "flutter/impeller/aiks/aiks_context.h"
#include "flutter/impeller/renderer/context.h"
#include "flutter/shell/gpu/gpu_surface_gl_delegate.h"
#include "impeller/renderer/renderer.h"
namespace flutter {

View File

@ -12,6 +12,7 @@
#include "flutter/impeller/aiks/aiks_context.h"
#include "flutter/impeller/renderer/context.h"
#include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h"
#include "impeller/renderer/renderer.h"
namespace flutter {

View File

@ -478,9 +478,6 @@ impeller_Play_AiksTest_CanRenderWithContiguousClipRestores_Vulkan.png
impeller_Play_AiksTest_CanSaveLayerStandalone_Metal.png
impeller_Play_AiksTest_CanSaveLayerStandalone_OpenGLES.png
impeller_Play_AiksTest_CanSaveLayerStandalone_Vulkan.png
impeller_Play_AiksTest_CaptureContext_Metal.png
impeller_Play_AiksTest_CaptureContext_OpenGLES.png
impeller_Play_AiksTest_CaptureContext_Vulkan.png
impeller_Play_AiksTest_ClearBlendWithBlur_Metal.png
impeller_Play_AiksTest_ClearBlendWithBlur_OpenGLES.png
impeller_Play_AiksTest_ClearBlendWithBlur_Vulkan.png