mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
* [fuchsia] Add labels to Scenic nodes. * [fuchsia] Skip creating Scenic nodes for identity Transforms. * [fuchsia] Assign elevation to Scenic nodes based on paint order. * [fuchsia] Create Scenic OpacityNodes at leaf nodes. * [fuchsia] Composite PhysicalShapeLayers using Skia, except when they need to float above child views. In that case, they will still need to be pulled into separate Scenic nodes to be composited on top of the child view[s]. * [fuchsia] Add tests for Fuchsia-specific layer behavior. Inspect commands going to Scenic and make sure they match what is expected. Also, restructure code to need less member variables, and other cleanups based on review feedback.
276 lines
9.5 KiB
C++
276 lines
9.5 KiB
C++
// 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_FLOW_SCENE_UPDATE_CONTEXT_H_
|
|
#define FLUTTER_FLOW_SCENE_UPDATE_CONTEXT_H_
|
|
|
|
#include <cfloat>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
#include "flutter/flow/compositor_context.h"
|
|
#include "flutter/flow/raster_cache_key.h"
|
|
#include "flutter/fml/compiler_specific.h"
|
|
#include "flutter/fml/logging.h"
|
|
#include "flutter/fml/macros.h"
|
|
#include "lib/ui/scenic/cpp/resources.h"
|
|
#include "third_party/skia/include/core/SkRect.h"
|
|
#include "third_party/skia/include/core/SkSurface.h"
|
|
|
|
namespace flutter {
|
|
|
|
class Layer;
|
|
|
|
// Scenic currently lacks an API to enable rendering of alpha channel; this only
|
|
// happens if there is a OpacityNode higher in the tree with opacity != 1. For
|
|
// now, clamp to a infinitesimally smaller value than 1, which does not cause
|
|
// visual problems in practice.
|
|
constexpr float kOneMinusEpsilon = 1 - FLT_EPSILON;
|
|
|
|
// How much layers are separated in Scenic z elevation.
|
|
constexpr float kScenicZElevationBetweenLayers = 10.f;
|
|
|
|
class SceneUpdateContext {
|
|
public:
|
|
class SurfaceProducerSurface {
|
|
public:
|
|
virtual ~SurfaceProducerSurface() = default;
|
|
|
|
virtual size_t AdvanceAndGetAge() = 0;
|
|
|
|
virtual bool FlushSessionAcquireAndReleaseEvents() = 0;
|
|
|
|
virtual bool IsValid() const = 0;
|
|
|
|
virtual SkISize GetSize() const = 0;
|
|
|
|
virtual void SignalWritesFinished(
|
|
const std::function<void(void)>& on_writes_committed) = 0;
|
|
|
|
virtual scenic::Image* GetImage() = 0;
|
|
|
|
virtual sk_sp<SkSurface> GetSkiaSurface() const = 0;
|
|
};
|
|
|
|
class SurfaceProducer {
|
|
public:
|
|
virtual ~SurfaceProducer() = default;
|
|
|
|
// The produced surface owns the entity_node and has a layer_key for
|
|
// retained rendering. The surface will only be retained if the layer_key
|
|
// has a non-null layer pointer (layer_key.id()).
|
|
virtual std::unique_ptr<SurfaceProducerSurface> ProduceSurface(
|
|
const SkISize& size,
|
|
const LayerRasterCacheKey& layer_key,
|
|
std::unique_ptr<scenic::EntityNode> entity_node) = 0;
|
|
|
|
// Query a retained entity node (owned by a retained surface) for retained
|
|
// rendering.
|
|
virtual bool HasRetainedNode(const LayerRasterCacheKey& key) const = 0;
|
|
virtual scenic::EntityNode* GetRetainedNode(
|
|
const LayerRasterCacheKey& key) = 0;
|
|
|
|
virtual void SubmitSurface(
|
|
std::unique_ptr<SurfaceProducerSurface> surface) = 0;
|
|
};
|
|
|
|
class Entity {
|
|
public:
|
|
Entity(SceneUpdateContext& context);
|
|
virtual ~Entity();
|
|
|
|
SceneUpdateContext& context() { return context_; }
|
|
scenic::EntityNode& entity_node() { return entity_node_; }
|
|
virtual scenic::ContainerNode& embedder_node() { return entity_node_; }
|
|
|
|
private:
|
|
SceneUpdateContext& context_;
|
|
Entity* const previous_entity_;
|
|
|
|
scenic::EntityNode entity_node_;
|
|
};
|
|
|
|
class Transform : public Entity {
|
|
public:
|
|
Transform(SceneUpdateContext& context, const SkMatrix& transform);
|
|
Transform(SceneUpdateContext& context,
|
|
float scale_x,
|
|
float scale_y,
|
|
float scale_z);
|
|
virtual ~Transform();
|
|
|
|
private:
|
|
float const previous_scale_x_;
|
|
float const previous_scale_y_;
|
|
};
|
|
|
|
class Frame : public Entity {
|
|
public:
|
|
// When layer is not nullptr, the frame is associated with a layer subtree
|
|
// rooted with that layer. The frame may then create a surface that will be
|
|
// retained for that layer.
|
|
Frame(SceneUpdateContext& context,
|
|
const SkRRect& rrect,
|
|
SkColor color,
|
|
SkAlpha opacity,
|
|
std::string label,
|
|
float z_translation = 0.0f,
|
|
Layer* layer = nullptr);
|
|
virtual ~Frame();
|
|
|
|
scenic::ContainerNode& embedder_node() override { return opacity_node_; }
|
|
|
|
void AddPaintLayer(Layer* layer);
|
|
|
|
private:
|
|
const SkRRect rrect_;
|
|
SkColor const color_;
|
|
SkAlpha const opacity_;
|
|
|
|
scenic::OpacityNodeHACK opacity_node_;
|
|
std::vector<Layer*> paint_layers_;
|
|
SkRect paint_bounds_;
|
|
Layer* layer_;
|
|
};
|
|
|
|
class Clip : public Entity {
|
|
public:
|
|
Clip(SceneUpdateContext& context, const SkRect& shape_bounds);
|
|
~Clip() = default;
|
|
};
|
|
|
|
SceneUpdateContext(scenic::Session* session,
|
|
SurfaceProducer* surface_producer);
|
|
~SceneUpdateContext() = default;
|
|
|
|
scenic::Session* session() { return session_; }
|
|
|
|
Entity* top_entity() { return top_entity_; }
|
|
|
|
bool has_metrics() const { return !!metrics_; }
|
|
void set_metrics(fuchsia::ui::gfx::MetricsPtr metrics) {
|
|
metrics_ = std::move(metrics);
|
|
}
|
|
const fuchsia::ui::gfx::MetricsPtr& metrics() const { return metrics_; }
|
|
|
|
void set_dimensions(const SkISize& frame_physical_size,
|
|
float frame_physical_depth,
|
|
float frame_device_pixel_ratio) {
|
|
frame_physical_size_ = frame_physical_size;
|
|
frame_physical_depth_ = frame_physical_depth;
|
|
frame_device_pixel_ratio_ = frame_device_pixel_ratio;
|
|
}
|
|
const SkISize& frame_size() const { return frame_physical_size_; }
|
|
float frame_physical_depth() const { return frame_physical_depth_; }
|
|
float frame_device_pixel_ratio() const { return frame_device_pixel_ratio_; }
|
|
|
|
// TODO(chinmaygarde): This method must submit the surfaces as soon as paint
|
|
// tasks are done. However, given that there is no support currently for
|
|
// Vulkan semaphores, we need to submit all the surfaces after an explicit
|
|
// CPU wait. Once Vulkan semaphores are available, this method must return
|
|
// void and the implementation must submit surfaces on its own as soon as the
|
|
// specific canvas operations are done.
|
|
[[nodiscard]] std::vector<std::unique_ptr<SurfaceProducerSurface>>
|
|
ExecutePaintTasks(CompositorContext::ScopedFrame& frame);
|
|
|
|
float ScaleX() const { return metrics_->scale_x * top_scale_x_; }
|
|
float ScaleY() const { return metrics_->scale_y * top_scale_y_; }
|
|
|
|
// The transformation matrix of the current context. It's used to construct
|
|
// the LayerRasterCacheKey for a given layer.
|
|
SkMatrix Matrix() const { return SkMatrix::MakeScale(ScaleX(), ScaleY()); }
|
|
|
|
bool HasRetainedNode(const LayerRasterCacheKey& key) const {
|
|
return surface_producer_->HasRetainedNode(key);
|
|
}
|
|
scenic::EntityNode* GetRetainedNode(const LayerRasterCacheKey& key) {
|
|
return surface_producer_->GetRetainedNode(key);
|
|
}
|
|
|
|
// The cumulative alpha value based on all the parent OpacityLayers.
|
|
void set_alphaf(float alpha) { alpha_ = alpha; }
|
|
float alphaf() { return alpha_; }
|
|
|
|
// The global scenic elevation at a given point in the traversal.
|
|
float scenic_elevation() { return scenic_elevation_; }
|
|
|
|
void set_scenic_elevation(float elevation) { scenic_elevation_ = elevation; }
|
|
|
|
float GetGlobalElevationForNextScenicLayer() {
|
|
float elevation = topmost_global_scenic_elevation_;
|
|
topmost_global_scenic_elevation_ += kScenicZElevationBetweenLayers;
|
|
return elevation;
|
|
}
|
|
|
|
private:
|
|
struct PaintTask {
|
|
std::unique_ptr<SurfaceProducerSurface> surface;
|
|
SkScalar left;
|
|
SkScalar top;
|
|
SkScalar scale_x;
|
|
SkScalar scale_y;
|
|
SkColor background_color;
|
|
std::vector<Layer*> layers;
|
|
};
|
|
|
|
// Setup the entity_node as a frame that materialize all the paint_layers. In
|
|
// most cases, this creates a VulkanSurface (SurfaceProducerSurface) by
|
|
// calling SetShapeTextureOrColor and GenerageImageIfNeeded. Such surface will
|
|
// own the associated entity_node. If the layer pointer isn't nullptr, the
|
|
// surface (and thus the entity_node) will be retained for that layer to
|
|
// improve the performance.
|
|
void CreateFrame(scenic::EntityNode entity_node,
|
|
const SkRRect& rrect,
|
|
SkColor color,
|
|
SkAlpha opacity,
|
|
const SkRect& paint_bounds,
|
|
std::vector<Layer*> paint_layers,
|
|
Layer* layer);
|
|
void SetMaterialTextureAndColor(scenic::Material& material,
|
|
SkColor color,
|
|
SkAlpha opacity,
|
|
SkScalar scale_x,
|
|
SkScalar scale_y,
|
|
const SkRect& paint_bounds,
|
|
std::vector<Layer*> paint_layers,
|
|
Layer* layer,
|
|
scenic::EntityNode entity_node);
|
|
void SetMaterialColor(scenic::Material& material,
|
|
SkColor color,
|
|
SkAlpha opacity);
|
|
scenic::Image* GenerateImageIfNeeded(SkColor color,
|
|
SkScalar scale_x,
|
|
SkScalar scale_y,
|
|
const SkRect& paint_bounds,
|
|
std::vector<Layer*> paint_layers,
|
|
Layer* layer,
|
|
scenic::EntityNode entity_node);
|
|
|
|
Entity* top_entity_ = nullptr;
|
|
float top_scale_x_ = 1.f;
|
|
float top_scale_y_ = 1.f;
|
|
|
|
scenic::Session* const session_;
|
|
SurfaceProducer* const surface_producer_;
|
|
|
|
fuchsia::ui::gfx::MetricsPtr metrics_;
|
|
SkISize frame_physical_size_;
|
|
float frame_physical_depth_ = 0.0f;
|
|
float frame_device_pixel_ratio_ =
|
|
1.0f; // Ratio between logical and physical pixels.
|
|
|
|
float alpha_ = 1.0f;
|
|
float scenic_elevation_ = 0.f;
|
|
float topmost_global_scenic_elevation_ = kScenicZElevationBetweenLayers;
|
|
|
|
std::vector<PaintTask> paint_tasks_;
|
|
|
|
FML_DISALLOW_COPY_AND_ASSIGN(SceneUpdateContext);
|
|
};
|
|
|
|
} // namespace flutter
|
|
|
|
#endif // FLUTTER_FLOW_SCENE_UPDATE_CONTEXT_H_
|