in shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc [108:330]
void FlatlandExternalViewEmbedder::SubmitFrame(
GrDirectContext* context,
std::unique_ptr<flutter::SurfaceFrame> frame) {
TRACE_EVENT0("flutter", "FlatlandExternalViewEmbedder::SubmitFrame");
std::vector<std::unique_ptr<SurfaceProducerSurface>> frame_surfaces;
std::unordered_map<EmbedderLayerId, size_t> frame_surface_indices;
// Create surfaces for the frame and associate them with layer IDs.
{
TRACE_EVENT0("flutter", "CreateSurfaces");
for (const auto& layer : frame_layers_) {
if (!layer.second.canvas_spy->DidDrawIntoCanvas()) {
continue;
}
auto surface =
surface_producer_->ProduceSurface(layer.second.surface_size);
if (!surface) {
const std::string layer_id_str =
layer.first.has_value() ? std::to_string(layer.first.value())
: "Background";
FML_LOG(ERROR) << "Failed to create surface for layer " << layer_id_str
<< "; size (" << layer.second.surface_size.width()
<< ", " << layer.second.surface_size.height() << ")";
FML_DCHECK(false);
continue;
}
// If we receive an unitialized surface, we need to first create flatland
// resource.
if (surface->GetImageId() == 0) {
auto image_id = flatland_->NextContentId().value;
const auto& size = surface->GetSize();
fuchsia::ui::composition::ImageProperties image_properties;
image_properties.set_size({static_cast<uint32_t>(size.width()),
static_cast<uint32_t>(size.height())});
flatland_->flatland()->CreateImage(
{image_id}, surface->GetBufferCollectionImportToken(), 0,
std::move(image_properties));
surface->SetImageId(image_id);
surface->SetReleaseImageCallback([flatland = flatland_, image_id]() {
flatland->flatland()->ReleaseImage({image_id});
});
}
// Enqueue fences for the next present.
flatland_->EnqueueAcquireFence(surface->GetAcquireFence());
flatland_->EnqueueReleaseFence(surface->GetReleaseFence());
frame_surface_indices.emplace(
std::make_pair(layer.first, frame_surfaces.size()));
frame_surfaces.emplace_back(std::move(surface));
}
}
// Submit layers and platform views to Scenic in composition order.
{
TRACE_EVENT0("flutter", "SubmitLayers");
size_t flatland_layer_index = 0;
for (const auto& layer_id : frame_composition_order_) {
const auto& layer = frame_layers_.find(layer_id);
FML_CHECK(layer != frame_layers_.end());
// Draw the PlatformView associated with each layer first.
if (layer_id.has_value()) {
FML_CHECK(layer->second.embedded_view_params.has_value());
auto& view_params = layer->second.embedded_view_params.value();
// Get the FlatlandView structure corresponding to the platform view.
auto found = flatland_views_.find(layer_id.value());
FML_CHECK(found != flatland_views_.end());
auto& viewport = found->second;
// Compute mutators, and size for the platform view.
const ViewMutators view_mutators =
ParseMutatorStack(view_params.mutatorsStack());
const SkSize view_size = view_params.sizePoints();
FML_CHECK(view_mutators.total_transform ==
view_params.transformMatrix());
// TODO(fxbug.dev/64201): Handle clips.
// Set transform for the viewport.
// TODO(fxbug.dev/64201): Handle scaling.
if (view_mutators.transform != viewport.mutators.transform) {
flatland_->flatland()->SetTranslation(
viewport.transform_id,
{static_cast<int32_t>(view_mutators.transform.getTranslateX()),
static_cast<int32_t>(view_mutators.transform.getTranslateY())});
viewport.mutators.transform = view_mutators.transform;
}
// TODO(fxbug.dev/64201): Set HitTestBehavior.
// TODO(fxbug.dev/64201): Set opacity.
// Set size
// TODO(): Set occlusion hint, and focusable.
if (view_size != viewport.size) {
fuchsia::ui::composition::ViewportProperties properties;
properties.set_logical_size(
{static_cast<uint32_t>(view_size.fWidth),
static_cast<uint32_t>(view_size.fHeight)});
flatland_->flatland()->SetViewportProperties(viewport.viewport_id,
std::move(properties));
viewport.size = view_size;
}
// Attach the FlatlandView to the main scene graph.
flatland_->flatland()->AddChild(root_transform_id_,
viewport.transform_id);
child_transforms_.emplace_back(viewport.transform_id);
}
// Acquire the surface associated with the layer.
SurfaceProducerSurface* surface_for_layer = nullptr;
if (layer->second.canvas_spy->DidDrawIntoCanvas()) {
const auto& surface_index = frame_surface_indices.find(layer_id);
if (surface_index != frame_surface_indices.end()) {
FML_CHECK(surface_index->second < frame_surfaces.size());
surface_for_layer = frame_surfaces[surface_index->second].get();
FML_CHECK(surface_for_layer != nullptr);
} else {
const std::string layer_id_str =
layer_id.has_value() ? std::to_string(layer_id.value())
: "Background";
FML_LOG(ERROR) << "Missing surface for layer " << layer_id_str
<< "; skipping scene graph add of layer.";
FML_DCHECK(false);
}
}
// Draw the layer if we acquired a surface for it successfully.
if (surface_for_layer != nullptr) {
// Create a new layer if needed for the surface.
FML_CHECK(flatland_layer_index <= flatland_layers_.size());
if (flatland_layer_index == flatland_layers_.size()) {
FlatlandLayer new_layer{.transform_id = flatland_->NextTransformId()};
flatland_->flatland()->CreateTransform(new_layer.transform_id);
flatland_layers_.emplace_back(std::move(new_layer));
}
// Update the image content and set size.
flatland_->flatland()->SetContent(
flatland_layers_[flatland_layer_index].transform_id,
{surface_for_layer->GetImageId()});
flatland_->flatland()->SetImageDestinationSize(
{surface_for_layer->GetImageId()},
{static_cast<uint32_t>(surface_for_layer->GetSize().width()),
static_cast<uint32_t>(surface_for_layer->GetSize().height())});
// Flutter Embedder lacks an API to detect if a layer has alpha or not.
// For now, we assume any layer beyond the first has alpha.
flatland_->flatland()->SetImageBlendingFunction(
{surface_for_layer->GetImageId()},
flatland_layer_index == 0
? fuchsia::ui::composition::BlendMode::SRC
: fuchsia::ui::composition::BlendMode::SRC_OVER);
// Attach the FlatlandLayer to the main scene graph.
flatland_->flatland()->AddChild(
root_transform_id_,
flatland_layers_[flatland_layer_index].transform_id);
child_transforms_.emplace_back(
flatland_layers_[flatland_layer_index].transform_id);
}
// Reset for the next pass:
flatland_layer_index++;
}
}
// Present the session to Scenic, along with surface acquire/release fences.
{
TRACE_EVENT0("flutter", "SessionPresent");
flatland_->Present();
}
// Render the recorded SkPictures into the surfaces.
{
TRACE_EVENT0("flutter", "RasterizeSurfaces");
for (const auto& surface_index : frame_surface_indices) {
TRACE_EVENT0("flutter", "RasterizeSurface");
FML_CHECK(surface_index.second < frame_surfaces.size());
SurfaceProducerSurface* surface =
frame_surfaces[surface_index.second].get();
FML_CHECK(surface != nullptr);
sk_sp<SkSurface> sk_surface = surface->GetSkiaSurface();
FML_CHECK(sk_surface != nullptr);
FML_CHECK(SkISize::Make(sk_surface->width(), sk_surface->height()) ==
frame_size_);
SkCanvas* canvas = sk_surface->getCanvas();
FML_CHECK(canvas != nullptr);
const auto& layer = frame_layers_.find(surface_index.first);
FML_CHECK(layer != frame_layers_.end());
sk_sp<SkPicture> picture =
layer->second.recorder->finishRecordingAsPicture();
FML_CHECK(picture != nullptr);
canvas->setMatrix(SkMatrix::I());
canvas->clear(SK_ColorTRANSPARENT);
canvas->drawPicture(picture);
canvas->flush();
}
}
// Flush deferred Skia work and inform Scenic that render targets are ready.
{
TRACE_EVENT0("flutter", "PresentSurfaces");
surface_producer_->SubmitSurfaces(std::move(frame_surfaces));
}
// Submit the underlying render-backend-specific frame for processing.
frame->Submit();
}