[scenic] Simplified gfx::Session
Pulled all the ApplyCommand stuff out of session into it's own GfxCommandApplier class to make Session more readable, and simplified the destruction of SessionHandler, so that it's now a two-way dependency between SessionHandler and SessionManager instead of a three-way dependency involving Session.
Also removed the exposed reference to scenic from CommandDispatcherContext mentioned in SCN-808.
SCN-1194 #done
SCN-808 #comment
Test: fx build-push scenic_tests && fx run-test scenic_tests
And manually verified that
killall basemgr
didn't kill scenic and that launching
fx shell set_root_view fuchsia-pkg://fuchsia.com/noodles#meta/noodles.cmx
worked afterwards
Change-Id: I51631862e22dd4bebb13946343ccda52aee0c5ea
diff --git a/bin/ui/BUILD.gn b/bin/ui/BUILD.gn
index 9db7743..da72969 100644
--- a/bin/ui/BUILD.gn
+++ b/bin/ui/BUILD.gn
@@ -76,6 +76,10 @@
dest = "input_unittests.cmx"
},
{
+ path = rebase_path("meta/scenic_unittests.cmx")
+ dest = "scenic_unittests.cmx"
+ },
+ {
path = rebase_path("meta/view_manager_apptests.cmx")
dest = "view_manager_apptests.cmx"
},
diff --git a/bin/ui/meta/scenic_unittests.cmx b/bin/ui/meta/scenic_unittests.cmx
new file mode 100644
index 0000000..30a58aa
--- /dev/null
+++ b/bin/ui/meta/scenic_unittests.cmx
@@ -0,0 +1,11 @@
+{
+ "program": {
+ "binary": "test/scenic_unittests"
+ },
+ "sandbox": {
+ "features": [ "vulkan" ],
+ "services": [
+ "fuchsia.vulkan.loader.Loader"
+ ]
+ }
+}
diff --git a/lib/ui/gfx/BUILD.gn b/lib/ui/gfx/BUILD.gn
index 24cc45e..afb865d 100644
--- a/lib/ui/gfx/BUILD.gn
+++ b/lib/ui/gfx/BUILD.gn
@@ -75,6 +75,8 @@
"engine/frame_scheduler.h",
"engine/frame_timings.cc",
"engine/frame_timings.h",
+ "engine/gfx_command_applier.cc",
+ "engine/gfx_command_applier.h",
"engine/hardware_layer_assignment.cc",
"engine/hardware_layer_assignment.h",
"engine/hit.h",
diff --git a/lib/ui/gfx/engine/gfx_command_applier.cc b/lib/ui/gfx/engine/gfx_command_applier.cc
new file mode 100644
index 0000000..fb13818
--- /dev/null
+++ b/lib/ui/gfx/engine/gfx_command_applier.cc
@@ -0,0 +1,1530 @@
+// Copyright 2019 The Fuchsia 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 "garnet/lib/ui/gfx/engine/gfx_command_applier.h"
+
+#include <lib/async/default.h>
+#include <trace/event.h>
+
+#include "garnet/lib/ui/gfx/engine/resource_linker.h"
+#include "garnet/lib/ui/gfx/resources/buffer.h"
+#include "garnet/lib/ui/gfx/resources/camera.h"
+#include "garnet/lib/ui/gfx/resources/compositor/display_compositor.h"
+#include "garnet/lib/ui/gfx/resources/compositor/layer.h"
+#include "garnet/lib/ui/gfx/resources/compositor/layer_stack.h"
+#include "garnet/lib/ui/gfx/resources/image.h"
+#include "garnet/lib/ui/gfx/resources/image_pipe.h"
+#include "garnet/lib/ui/gfx/resources/image_pipe_handler.h"
+#include "garnet/lib/ui/gfx/resources/lights/ambient_light.h"
+#include "garnet/lib/ui/gfx/resources/lights/directional_light.h"
+#include "garnet/lib/ui/gfx/resources/memory.h"
+#include "garnet/lib/ui/gfx/resources/nodes/entity_node.h"
+#include "garnet/lib/ui/gfx/resources/nodes/node.h"
+#include "garnet/lib/ui/gfx/resources/nodes/opacity_node.h"
+#include "garnet/lib/ui/gfx/resources/nodes/scene.h"
+#include "garnet/lib/ui/gfx/resources/nodes/shape_node.h"
+#include "garnet/lib/ui/gfx/resources/renderers/renderer.h"
+#include "garnet/lib/ui/gfx/resources/shapes/circle_shape.h"
+#include "garnet/lib/ui/gfx/resources/shapes/mesh_shape.h"
+#include "garnet/lib/ui/gfx/resources/shapes/rectangle_shape.h"
+#include "garnet/lib/ui/gfx/resources/shapes/rounded_rectangle_shape.h"
+#include "garnet/lib/ui/gfx/resources/snapshot/snapshotter.h"
+#include "garnet/lib/ui/gfx/resources/stereo_camera.h"
+#include "garnet/lib/ui/gfx/resources/variable.h"
+#include "garnet/lib/ui/gfx/resources/view.h"
+#include "garnet/lib/ui/gfx/resources/view_holder.h"
+
+#include "garnet/lib/ui/gfx/engine/hit_tester.h"
+#include "garnet/lib/ui/gfx/engine/session_handler.h"
+#include "garnet/lib/ui/gfx/swapchain/swapchain_factory.h"
+#include "garnet/lib/ui/gfx/util/time.h"
+#include "garnet/lib/ui/gfx/util/unwrap.h"
+#include "garnet/lib/ui/gfx/util/wrap.h"
+#include "garnet/lib/ui/scenic/util/print_command.h"
+#include "lib/escher/hmd/pose_buffer.h"
+#include "lib/escher/renderer/batch_gpu_uploader.h"
+#include "lib/escher/shape/mesh.h"
+#include "lib/escher/shape/rounded_rect_factory.h"
+#include "lib/escher/util/type_utils.h"
+
+namespace scenic_impl {
+namespace gfx {
+
+namespace {
+
+// Makes it convenient to check that a value is constant and of a specific type,
+// or a variable.
+// TODO: There should also be a convenient way of type-checking a variable;
+// this will necessarily involve looking up the value in the ResourceMap.
+constexpr std::array<fuchsia::ui::gfx::Value::Tag, 2> kFloatValueTypes{
+ {fuchsia::ui::gfx::Value::Tag::kVector1,
+ fuchsia::ui::gfx::Value::Tag::kVariableId}};
+
+} // anonymous namespace
+
+bool GfxCommandApplier::AssertValueIsOfType(
+ const fuchsia::ui::gfx::Value& value,
+ const fuchsia::ui::gfx::Value::Tag* tags, size_t tag_count,
+ Session* session) {
+ using ::operator<<; // From print_commands.h
+ FXL_DCHECK(tag_count > 0);
+ for (size_t i = 0; i < tag_count; ++i) {
+ if (value.Which() == tags[i]) {
+ return true;
+ }
+ }
+ std::ostringstream str;
+ if (tag_count == 1) {
+ str << ", which is not the expected type: " << tags[0] << ".";
+ } else {
+ str << ", which is not one of the expected types (" << tags[0];
+ for (size_t i = 1; i < tag_count; ++i) {
+ str << ", " << tags[i];
+ }
+ str << ").";
+ }
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::Session: received value of type: " << value.Which()
+ << str.str();
+ return false;
+}
+
+bool GfxCommandApplier::ApplyCommand(Session* session,
+ CommandContext* command_context,
+ fuchsia::ui::gfx::Command command) {
+ TRACE_DURATION("gfx", "GfxCommandApplier::ApplyCommand");
+
+ switch (command.Which()) {
+ case fuchsia::ui::gfx::Command::Tag::kCreateResource:
+ return ApplyCreateResourceCmd(session, command_context,
+ std::move(command.create_resource()));
+ case fuchsia::ui::gfx::Command::Tag::kReleaseResource:
+ return ApplyReleaseResourceCmd(session,
+ std::move(command.release_resource()));
+ case fuchsia::ui::gfx::Command::Tag::kExportResource:
+ return ApplyExportResourceCmd(session,
+ std::move(command.export_resource()));
+ case fuchsia::ui::gfx::Command::Tag::kImportResource:
+ return ApplyImportResourceCmd(session,
+ std::move(command.import_resource()));
+ case fuchsia::ui::gfx::Command::Tag::kSetImportFocus: {
+ // TODO(SCN-1026): Remove this.
+ if (auto import = session->resources()->FindResource<Import>(
+ command.set_import_focus().id,
+ ResourceMap::ErrorBehavior::kDontReportErrors)) {
+ import->set_focusable(command.set_import_focus().focusable);
+ return true;
+ }
+ return false;
+ }
+ case fuchsia::ui::gfx::Command::Tag::kAddChild:
+ return ApplyAddChildCmd(session, std::move(command.add_child()));
+ case fuchsia::ui::gfx::Command::Tag::kAddPart:
+ return ApplyAddPartCmd(session, std::move(command.add_part()));
+ case fuchsia::ui::gfx::Command::Tag::kDetach:
+ return ApplyDetachCmd(session, std::move(command.detach()));
+ case fuchsia::ui::gfx::Command::Tag::kDetachChildren:
+ return ApplyDetachChildrenCmd(session,
+ std::move(command.detach_children()));
+ case fuchsia::ui::gfx::Command::Tag::kSetTag:
+ return ApplySetTagCmd(session, std::move(command.set_tag()));
+ case fuchsia::ui::gfx::Command::Tag::kSetTranslation:
+ return ApplySetTranslationCmd(session,
+ std::move(command.set_translation()));
+ case fuchsia::ui::gfx::Command::Tag::kSetScale:
+ return ApplySetScaleCmd(session, std::move(command.set_scale()));
+ case fuchsia::ui::gfx::Command::Tag::kSetRotation:
+ return ApplySetRotationCmd(session, std::move(command.set_rotation()));
+ case fuchsia::ui::gfx::Command::Tag::kSetAnchor:
+ return ApplySetAnchorCmd(session, std::move(command.set_anchor()));
+ case fuchsia::ui::gfx::Command::Tag::kSetSize:
+ return ApplySetSizeCmd(session, std::move(command.set_size()));
+ case fuchsia::ui::gfx::Command::Tag::kSetOpacity:
+ return ApplySetOpacityCmd(session, command.set_opacity());
+ case fuchsia::ui::gfx::Command::Tag::kSendSizeChangeHintHack:
+ return ApplySendSizeChangeHintCmd(session,
+ command.send_size_change_hint_hack());
+ case fuchsia::ui::gfx::Command::Tag::kSetShape:
+ return ApplySetShapeCmd(session, std::move(command.set_shape()));
+ case fuchsia::ui::gfx::Command::Tag::kSetMaterial:
+ return ApplySetMaterialCmd(session, std::move(command.set_material()));
+ case fuchsia::ui::gfx::Command::Tag::kSetClip:
+ return ApplySetClipCmd(session, std::move(command.set_clip()));
+ case fuchsia::ui::gfx::Command::Tag::kSetHitTestBehavior:
+ return ApplySetHitTestBehaviorCmd(
+ session, std::move(command.set_hit_test_behavior()));
+ case fuchsia::ui::gfx::Command::Tag::kSetViewProperties:
+ return ApplySetViewPropertiesCmd(
+ session, std::move(command.set_view_properties()));
+ case fuchsia::ui::gfx::Command::Tag::kSetCamera:
+ return ApplySetCameraCmd(session, std::move(command.set_camera()));
+ case fuchsia::ui::gfx::Command::Tag::kSetCameraTransform:
+ return ApplySetCameraTransformCmd(
+ session, std::move(command.set_camera_transform()));
+ case fuchsia::ui::gfx::Command::Tag::kSetCameraProjection:
+ return ApplySetCameraProjectionCmd(
+ session, std::move(command.set_camera_projection()));
+ case fuchsia::ui::gfx::Command::Tag::kSetStereoCameraProjection:
+ return ApplySetStereoCameraProjectionCmd(
+ session, std::move(command.set_stereo_camera_projection()));
+ case fuchsia::ui::gfx::Command::Tag::kSetCameraPoseBuffer:
+ return ApplySetCameraPoseBufferCmd(
+ session, std::move(command.set_camera_pose_buffer()));
+ case fuchsia::ui::gfx::Command::Tag::kSetLightColor:
+ return ApplySetLightColorCmd(session,
+ std::move(command.set_light_color()));
+ case fuchsia::ui::gfx::Command::Tag::kSetLightDirection:
+ return ApplySetLightDirectionCmd(
+ session, std::move(command.set_light_direction()));
+ case fuchsia::ui::gfx::Command::Tag::kAddLight:
+ return ApplyAddLightCmd(session, std::move(command.add_light()));
+ case fuchsia::ui::gfx::Command::Tag::kDetachLight:
+ return ApplyDetachLightCmd(session, std::move(command.detach_light()));
+ case fuchsia::ui::gfx::Command::Tag::kDetachLights:
+ return ApplyDetachLightsCmd(session, std::move(command.detach_lights()));
+ case fuchsia::ui::gfx::Command::Tag::kSetTexture:
+ return ApplySetTextureCmd(session, std::move(command.set_texture()));
+ case fuchsia::ui::gfx::Command::Tag::kSetColor:
+ return ApplySetColorCmd(session, std::move(command.set_color()));
+ case fuchsia::ui::gfx::Command::Tag::kBindMeshBuffers:
+ return ApplyBindMeshBuffersCmd(session,
+ std::move(command.bind_mesh_buffers()));
+ case fuchsia::ui::gfx::Command::Tag::kAddLayer:
+ return ApplyAddLayerCmd(session, std::move(command.add_layer()));
+ case fuchsia::ui::gfx::Command::Tag::kRemoveLayer:
+ return ApplyRemoveLayerCmd(session, std::move(command.remove_layer()));
+ case fuchsia::ui::gfx::Command::Tag::kRemoveAllLayers:
+ return ApplyRemoveAllLayersCmd(session,
+ std::move(command.remove_all_layers()));
+ case fuchsia::ui::gfx::Command::Tag::kSetLayerStack:
+ return ApplySetLayerStackCmd(session,
+ std::move(command.set_layer_stack()));
+ case fuchsia::ui::gfx::Command::Tag::kSetRenderer:
+ return ApplySetRendererCmd(session, std::move(command.set_renderer()));
+ case fuchsia::ui::gfx::Command::Tag::kSetRendererParam:
+ return ApplySetRendererParamCmd(session,
+ std::move(command.set_renderer_param()));
+ case fuchsia::ui::gfx::Command::Tag::kSetEventMask:
+ return ApplySetEventMaskCmd(session, std::move(command.set_event_mask()));
+ case fuchsia::ui::gfx::Command::Tag::kSetLabel:
+ return ApplySetLabelCmd(session, std::move(command.set_label()));
+ case fuchsia::ui::gfx::Command::Tag::kSetDisableClipping:
+ return ApplySetDisableClippingCmd(
+ session, std::move(command.set_disable_clipping()));
+ case fuchsia::ui::gfx::Command::Tag::kTakeSnapshotCmd:
+ return ApplyTakeSnapshotCmdHACK(session,
+ std::move(command.take_snapshot_cmd()));
+ case fuchsia::ui::gfx::Command::Tag::Invalid:
+ // FIDL validation should make this impossible.
+ FXL_CHECK(false);
+ return false;
+ }
+}
+
+bool GfxCommandApplier::ApplyCreateResourceCmd(
+ Session* session, CommandContext* command_context,
+ fuchsia::ui::gfx::CreateResourceCmd command) {
+ const ResourceId id = command.id;
+ if (id == 0) {
+ using ::operator<<; // From print_commands.h
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplyCreateResourceCmd(): invalid ID: "
+ << command;
+ return false;
+ }
+
+ switch (command.resource.Which()) {
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kMemory:
+ return ApplyCreateMemory(session, id,
+ std::move(command.resource.memory()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kImage:
+ return ApplyCreateImage(session, id, std::move(command.resource.image()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kImagePipe:
+ return ApplyCreateImagePipe(session, id,
+ std::move(command.resource.image_pipe()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kBuffer:
+ return ApplyCreateBuffer(session, id,
+ std::move(command.resource.buffer()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kScene:
+ return ApplyCreateScene(session, id, std::move(command.resource.scene()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kCamera:
+ return ApplyCreateCamera(session, id,
+ std::move(command.resource.camera()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kStereoCamera:
+ return ApplyCreateStereoCamera(
+ session, id, std::move(command.resource.stereo_camera()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kRenderer:
+ return ApplyCreateRenderer(session, id,
+ std::move(command.resource.renderer()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kAmbientLight:
+ return ApplyCreateAmbientLight(
+ session, id, std::move(command.resource.ambient_light()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kDirectionalLight:
+ return ApplyCreateDirectionalLight(
+ session, id, std::move(command.resource.directional_light()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kRectangle:
+ return ApplyCreateRectangle(session, id,
+ std::move(command.resource.rectangle()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kRoundedRectangle:
+ return ApplyCreateRoundedRectangle(
+ session, command_context, id,
+ std::move(command.resource.rounded_rectangle()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kCircle:
+ return ApplyCreateCircle(session, id,
+ std::move(command.resource.circle()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kMesh:
+ return ApplyCreateMesh(session, id, std::move(command.resource.mesh()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kMaterial:
+ return ApplyCreateMaterial(session, id,
+ std::move(command.resource.material()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kView:
+ return ApplyCreateView(session, id, std::move(command.resource.view()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kViewHolder:
+ return ApplyCreateViewHolder(session, id,
+ std::move(command.resource.view_holder()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kClipNode:
+ return ApplyCreateClipNode(session, id,
+ std::move(command.resource.clip_node()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kOpacityNode:
+ return ApplyCreateOpacityNode(session, id,
+ command.resource.opacity_node());
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kEntityNode:
+ return ApplyCreateEntityNode(session, id,
+ std::move(command.resource.entity_node()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kShapeNode:
+ return ApplyCreateShapeNode(session, id,
+ std::move(command.resource.shape_node()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kCompositor:
+ return ApplyCreateCompositor(session, id,
+ std::move(command.resource.compositor()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kDisplayCompositor:
+ return ApplyCreateDisplayCompositor(
+ session, id, std::move(command.resource.display_compositor()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kImagePipeCompositor:
+ return ApplyCreateImagePipeCompositor(
+ session, id, std::move(command.resource.image_pipe_compositor()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kLayerStack:
+ return ApplyCreateLayerStack(session, id,
+ std::move(command.resource.layer_stack()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kLayer:
+ return ApplyCreateLayer(session, id, std::move(command.resource.layer()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::kVariable:
+ return ApplyCreateVariable(session, id,
+ std::move(command.resource.variable()));
+ case fuchsia::ui::gfx::ResourceArgs::Tag::Invalid:
+ // FIDL validation should make this impossible.
+ FXL_CHECK(false);
+ return false;
+ }
+}
+
+bool GfxCommandApplier::ApplyReleaseResourceCmd(
+ Session* session, fuchsia::ui::gfx::ReleaseResourceCmd command) {
+ return session->resources()->RemoveResource(command.id);
+}
+
+bool GfxCommandApplier::ApplyExportResourceCmd(
+ Session* session, fuchsia::ui::gfx::ExportResourceCmd command) {
+ if (!command.token) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::ApplyExportResourceCmd(): "
+ "no token provided.";
+ return false;
+ }
+ if (auto resource =
+ session->resources()->FindResource<Resource>(command.id)) {
+ return session->session_context().resource_linker->ExportResource(
+ resource.get(), std::move(command.token));
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplyImportResourceCmd(
+ Session* session, fuchsia::ui::gfx::ImportResourceCmd command) {
+ if (!command.token) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::ApplyImportResourceCmd(): "
+ "no token provided.";
+ return false;
+ }
+ auto import = fxl::MakeRefCounted<Import>(
+ session, command.id, command.spec,
+ session->session_context().resource_linker->GetWeakPtr());
+ return session->session_context().resource_linker->ImportResource(
+ import.get(), command.spec, std::move(command.token)) &&
+ session->resources()->AddResource(command.id, std::move(import));
+}
+
+bool GfxCommandApplier::ApplyAddChildCmd(
+ Session* session, fuchsia::ui::gfx::AddChildCmd command) {
+ // Find the parent and child nodes. We can add:
+ // - Nodes to Nodes
+ // - ViewHolders to Nodes
+ // - Nodes to Views
+ // TODO(SCN-795): Split these out into separate commands?
+ if (auto parent = session->resources()->FindResource<Node>(
+ command.node_id, ResourceMap::ErrorBehavior::kDontReportErrors)) {
+ if (auto child = session->resources()->FindResource<Node>(
+ command.child_id, ResourceMap::ErrorBehavior::kDontReportErrors)) {
+ return parent->AddChild(std::move(child));
+ } else if (auto child = session->resources()->FindResource<ViewHolder>(
+ command.child_id)) {
+ return parent->AddViewHolder(std::move(child));
+ }
+ } else if (auto parent =
+ session->resources()->FindResource<View>(command.node_id)) {
+ if (auto child =
+ session->resources()->FindResource<Node>(command.child_id)) {
+ return parent->AddChild(std::move(child));
+ }
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplyAddPartCmd(Session* session,
+ fuchsia::ui::gfx::AddPartCmd command) {
+ // Find the parent and part nodes.
+ if (auto parent_node =
+ session->resources()->FindResource<Node>(command.node_id)) {
+ if (auto part_node =
+ session->resources()->FindResource<Node>(command.part_id)) {
+ return parent_node->AddPart(std::move(part_node));
+ }
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplyTakeSnapshotCmdHACK(
+ Session* session, fuchsia::ui::gfx::TakeSnapshotCmdHACK command) {
+ async::PostTask(
+ async_get_default_dispatcher(),
+ [weak = session->GetWeakPtr(), command = std::move(command)]() mutable {
+ if (!weak) {
+ if (auto callback = command.callback.Bind()) {
+ // TODO(SCN-978): Return an error to the caller for invalid data.
+ callback->OnData(fuchsia::mem::Buffer{});
+ }
+ return;
+ }
+
+ const auto& context = weak->session_context();
+ Resource* resource = nullptr;
+ if (auto node =
+ weak->resources()->FindResource<Node>(command.node_id)) {
+ resource = node.get();
+ } else if (command.node_id == 0) {
+ // TODO(SCN-1170): get rid of SceneGraph::first_compositor().
+ const auto& first_compositor_weak =
+ context.scene_graph->first_compositor();
+ if (first_compositor_weak) {
+ resource = first_compositor_weak.get();
+ }
+ }
+
+ if (resource == nullptr) {
+ if (auto callback = command.callback.Bind()) {
+ callback->OnData(fuchsia::mem::Buffer{});
+ }
+ return;
+ }
+
+ auto gpu_uploader =
+ escher::BatchGpuUploader::New(context.escher->GetWeakPtr());
+ Snapshotter snapshotter(gpu_uploader);
+ // Take a snapshot and return the data in callback. The closure does
+ // not need the snapshotter instance and is invoked after the instance
+ // is destroyed.
+ snapshotter.TakeSnapshot(resource, [callback = command.callback.Bind()](
+ fuchsia::mem::Buffer snapshot) {
+ callback->OnData(std::move(snapshot));
+ });
+ });
+ return true;
+}
+
+bool GfxCommandApplier::ApplyDetachCmd(Session* session,
+ fuchsia::ui::gfx::DetachCmd command) {
+ if (auto resource =
+ session->resources()->FindResource<Resource>(command.id)) {
+ return resource->Detach();
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplyDetachChildrenCmd(
+ Session* session, fuchsia::ui::gfx::DetachChildrenCmd command) {
+ if (auto node = session->resources()->FindResource<Node>(command.node_id)) {
+ return node->DetachChildren();
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetTagCmd(Session* session,
+ fuchsia::ui::gfx::SetTagCmd command) {
+ if (auto node = session->resources()->FindResource<Node>(command.node_id)) {
+ return node->SetTagValue(command.tag_value);
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetTranslationCmd(
+ Session* session, fuchsia::ui::gfx::SetTranslationCmd command) {
+ if (auto node = session->resources()->FindResource<Node>(command.id)) {
+ if (IsVariable(command.value)) {
+ if (auto variable =
+ session->resources()->FindVariableResource<Vector3Variable>(
+ command.value.variable_id)) {
+ return node->SetTranslation(variable);
+ }
+ } else {
+ return node->SetTranslation(UnwrapVector3(command.value));
+ }
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetScaleCmd(
+ Session* session, fuchsia::ui::gfx::SetScaleCmd command) {
+ if (auto node = session->resources()->FindResource<Node>(command.id)) {
+ if (IsVariable(command.value)) {
+ if (auto variable =
+ session->resources()->FindVariableResource<Vector3Variable>(
+ command.value.variable_id)) {
+ return node->SetScale(variable);
+ }
+ } else {
+ return node->SetScale(UnwrapVector3(command.value));
+ }
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetRotationCmd(
+ Session* session, fuchsia::ui::gfx::SetRotationCmd command) {
+ if (auto node = session->resources()->FindResource<Node>(command.id)) {
+ if (IsVariable(command.value)) {
+ if (auto variable =
+ session->resources()->FindVariableResource<QuaternionVariable>(
+ command.value.variable_id)) {
+ return node->SetRotation(variable);
+ }
+ } else {
+ return node->SetRotation(UnwrapQuaternion(command.value));
+ }
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetAnchorCmd(
+ Session* session, fuchsia::ui::gfx::SetAnchorCmd command) {
+ if (auto node = session->resources()->FindResource<Node>(command.id)) {
+ if (IsVariable(command.value)) {
+ if (auto variable =
+ session->resources()->FindVariableResource<Vector3Variable>(
+ command.value.variable_id)) {
+ return node->SetAnchor(variable);
+ }
+ }
+ return node->SetAnchor(UnwrapVector3(command.value));
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetSizeCmd(Session* session,
+ fuchsia::ui::gfx::SetSizeCmd command) {
+ if (auto layer = session->resources()->FindResource<Layer>(command.id)) {
+ if (IsVariable(command.value)) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::ApplySetSizeCmd(): "
+ "unimplemented for variable value.";
+ return false;
+ }
+ return layer->SetSize(UnwrapVector2(command.value));
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetOpacityCmd(
+ Session* session, fuchsia::ui::gfx::SetOpacityCmd command) {
+ if (auto node =
+ session->resources()->FindResource<OpacityNode>(command.node_id)) {
+ node->SetOpacity(command.opacity);
+ return true;
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySendSizeChangeHintCmd(
+ Session* session, fuchsia::ui::gfx::SendSizeChangeHintCmdHACK command) {
+ if (auto node = session->resources()->FindResource<Node>(command.node_id)) {
+ return node->SendSizeChangeHint(command.width_change_factor,
+ command.height_change_factor);
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetShapeCmd(
+ Session* session, fuchsia::ui::gfx::SetShapeCmd command) {
+ if (auto node =
+ session->resources()->FindResource<ShapeNode>(command.node_id)) {
+ if (auto shape =
+ session->resources()->FindResource<Shape>(command.shape_id)) {
+ node->SetShape(std::move(shape));
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetMaterialCmd(
+ Session* session, fuchsia::ui::gfx::SetMaterialCmd command) {
+ if (auto node =
+ session->resources()->FindResource<ShapeNode>(command.node_id)) {
+ if (auto material =
+ session->resources()->FindResource<Material>(command.material_id)) {
+ node->SetMaterial(std::move(material));
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetClipCmd(Session* session,
+ fuchsia::ui::gfx::SetClipCmd command) {
+ if (command.clip_id != 0) {
+ // TODO(SCN-167): Support non-zero clip_id.
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::ApplySetClipCmd(): only "
+ "clip_to_self is implemented.";
+ return false;
+ }
+
+ if (auto node = session->resources()->FindResource<Node>(command.node_id)) {
+ return node->SetClipToSelf(command.clip_to_self);
+ }
+
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetHitTestBehaviorCmd(
+ Session* session, fuchsia::ui::gfx::SetHitTestBehaviorCmd command) {
+ if (auto node = session->resources()->FindResource<Node>(command.node_id)) {
+ return node->SetHitTestBehavior(command.hit_test_behavior);
+ }
+
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetViewPropertiesCmd(
+ Session* session, fuchsia::ui::gfx::SetViewPropertiesCmd command) {
+ if (auto view_holder = session->resources()->FindResource<ViewHolder>(
+ command.view_holder_id)) {
+ view_holder->SetViewProperties(std::move(command.properties));
+ return true;
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetCameraCmd(
+ Session* session, fuchsia::ui::gfx::SetCameraCmd command) {
+ if (auto renderer =
+ session->resources()->FindResource<Renderer>(command.renderer_id)) {
+ if (command.camera_id == 0) {
+ renderer->SetCamera(nullptr);
+ return true;
+ } else if (auto camera = session->resources()->FindResource<Camera>(
+ command.camera_id)) {
+ renderer->SetCamera(std::move(camera));
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetTextureCmd(
+ Session* session, fuchsia::ui::gfx::SetTextureCmd command) {
+ if (auto material =
+ session->resources()->FindResource<Material>(command.material_id)) {
+ if (command.texture_id == 0) {
+ material->SetTexture(nullptr);
+ return true;
+ } else if (auto image = session->resources()->FindResource<ImageBase>(
+ command.texture_id)) {
+ material->SetTexture(std::move(image));
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetColorCmd(
+ Session* session, fuchsia::ui::gfx::SetColorCmd command) {
+ if (auto material =
+ session->resources()->FindResource<Material>(command.material_id)) {
+ if (IsVariable(command.color)) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::ApplySetColorCmd(): "
+ "unimplemented for variable color.";
+ return false;
+ }
+
+ auto& color = command.color.value;
+ float red = static_cast<float>(color.red) / 255.f;
+ float green = static_cast<float>(color.green) / 255.f;
+ float blue = static_cast<float>(color.blue) / 255.f;
+ float alpha = static_cast<float>(color.alpha) / 255.f;
+ material->SetColor(red, green, blue, alpha);
+ return true;
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplyBindMeshBuffersCmd(
+ Session* session, fuchsia::ui::gfx::BindMeshBuffersCmd command) {
+ auto mesh = session->resources()->FindResource<MeshShape>(command.mesh_id);
+ auto index_buffer =
+ session->resources()->FindResource<Buffer>(command.index_buffer_id);
+ auto vertex_buffer =
+ session->resources()->FindResource<Buffer>(command.vertex_buffer_id);
+ if (mesh && index_buffer && vertex_buffer) {
+ return mesh->BindBuffers(std::move(index_buffer), command.index_format,
+ command.index_offset, command.index_count,
+ std::move(vertex_buffer), command.vertex_format,
+ command.vertex_offset, command.vertex_count,
+ Unwrap(command.bounding_box));
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplyAddLayerCmd(
+ Session* session, fuchsia::ui::gfx::AddLayerCmd command) {
+ auto layer_stack =
+ session->resources()->FindResource<LayerStack>(command.layer_stack_id);
+ auto layer = session->resources()->FindResource<Layer>(command.layer_id);
+ if (layer_stack && layer) {
+ return layer_stack->AddLayer(std::move(layer));
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplyRemoveLayerCmd(
+ Session* session, fuchsia::ui::gfx::RemoveLayerCmd command) {
+ auto layer_stack =
+ session->resources()->FindResource<LayerStack>(command.layer_stack_id);
+ auto layer = session->resources()->FindResource<Layer>(command.layer_id);
+ if (layer_stack && layer) {
+ return layer_stack->RemoveLayer(std::move(layer));
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplyRemoveAllLayersCmd(
+ Session* session, fuchsia::ui::gfx::RemoveAllLayersCmd command) {
+ auto layer_stack =
+ session->resources()->FindResource<LayerStack>(command.layer_stack_id);
+ if (layer_stack) {
+ return layer_stack->RemoveAllLayers();
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetLayerStackCmd(
+ Session* session, fuchsia::ui::gfx::SetLayerStackCmd command) {
+ auto compositor =
+ session->resources()->FindResource<Compositor>(command.compositor_id);
+ auto layer_stack =
+ session->resources()->FindResource<LayerStack>(command.layer_stack_id);
+ if (compositor && layer_stack) {
+ return compositor->SetLayerStack(std::move(layer_stack));
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetRendererCmd(
+ Session* session, fuchsia::ui::gfx::SetRendererCmd command) {
+ auto layer = session->resources()->FindResource<Layer>(command.layer_id);
+ auto renderer =
+ session->resources()->FindResource<Renderer>(command.renderer_id);
+
+ if (layer && renderer) {
+ return layer->SetRenderer(std::move(renderer));
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetRendererParamCmd(
+ Session* session, fuchsia::ui::gfx::SetRendererParamCmd command) {
+ auto renderer =
+ session->resources()->FindResource<Renderer>(command.renderer_id);
+ if (renderer) {
+ switch (command.param.Which()) {
+ case fuchsia::ui::gfx::RendererParam::Tag::kShadowTechnique:
+ return renderer->SetShadowTechnique(command.param.shadow_technique());
+ case fuchsia::ui::gfx::RendererParam::Tag::kRenderFrequency:
+ // TODO(SCN-1169): SetRenderContinuously should only affect the
+ // compositor that has the renderer attached to it.
+ session->session_context().frame_scheduler->SetRenderContinuously(
+ command.param.render_frequency() ==
+ fuchsia::ui::gfx::RenderFrequency::CONTINUOUSLY);
+ return true;
+ case fuchsia::ui::gfx::RendererParam::Tag::Invalid:
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplySetRendererParamCmd(): "
+ "invalid param.";
+ }
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetEventMaskCmd(
+ Session* session, fuchsia::ui::gfx::SetEventMaskCmd command) {
+ if (auto r = session->resources()->FindResource<Resource>(command.id)) {
+ return r->SetEventMask(command.event_mask);
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetCameraTransformCmd(
+ Session* session, fuchsia::ui::gfx::SetCameraTransformCmd command) {
+ // TODO(SCN-123): support variables.
+ if (IsVariable(command.eye_position) || IsVariable(command.eye_look_at) ||
+ IsVariable(command.eye_up)) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplySetCameraTransformCmd(): "
+ "unimplemented: variable properties.";
+ return false;
+ } else if (auto camera = session->resources()->FindResource<Camera>(
+ command.camera_id)) {
+ camera->SetTransform(UnwrapVector3(command.eye_position),
+ UnwrapVector3(command.eye_look_at),
+ UnwrapVector3(command.eye_up));
+ return true;
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetCameraProjectionCmd(
+ Session* session, fuchsia::ui::gfx::SetCameraProjectionCmd command) {
+ // TODO(SCN-123): support variables.
+ if (IsVariable(command.fovy)) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplySetCameraProjectionCmd(): "
+ "unimplemented: variable properties.";
+ return false;
+ } else if (auto camera = session->resources()->FindResource<Camera>(
+ command.camera_id)) {
+ camera->SetProjection(UnwrapFloat(command.fovy));
+ return true;
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetStereoCameraProjectionCmd(
+ Session* session, fuchsia::ui::gfx::SetStereoCameraProjectionCmd command) {
+ if (IsVariable(command.left_projection) ||
+ IsVariable(command.right_projection)) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplySetStereoCameraProjectionOp(): "
+ "unimplemented: variable properties.";
+ return false;
+ } else if (auto stereo_camera =
+ session->resources()->FindResource<StereoCamera>(
+ command.camera_id)) {
+ stereo_camera->SetStereoProjection(Unwrap(command.left_projection.value),
+ Unwrap(command.right_projection.value));
+ return true;
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetCameraPoseBufferCmd(
+ Session* session, fuchsia::ui::gfx::SetCameraPoseBufferCmd command) {
+ if (command.base_time > dispatcher_clock_now()) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplySetCameraPoseBufferCmd(): "
+ "base time not in the past";
+ return false;
+ }
+
+ auto buffer = session->resources()->FindResource<Buffer>(command.buffer_id);
+ if (!buffer) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplySetCameraPoseBufferCmd(S): "
+ "invalid buffer ID";
+ return false;
+ }
+
+ if (command.num_entries < 1) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplySetCameraPoseBufferCmd(): "
+ "must have at least one entry in the pose buffer";
+ return false;
+ }
+
+ if (buffer->size() < command.num_entries * sizeof(escher::hmd::Pose)) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplySetCameraPoseBufferCmd(): "
+ "buffer is not large enough";
+ return false;
+ }
+
+ auto camera = session->resources()->FindResource<Camera>(command.camera_id);
+ if (!camera) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplySetCameraPoseBufferCmd(): "
+ "invalid camera ID";
+ return false;
+ }
+
+ camera->SetPoseBuffer(buffer, command.num_entries, command.base_time,
+ command.time_interval);
+
+ return true;
+}
+
+bool GfxCommandApplier::ApplySetLightColorCmd(
+ Session* session, fuchsia::ui::gfx::SetLightColorCmd command) {
+ // TODO(SCN-123): support variables.
+ if (command.color.variable_id) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::ApplySetLightColorCmd(): "
+ "unimplemented: variable color.";
+ return false;
+ } else if (auto light =
+ session->resources()->FindResource<Light>(command.light_id)) {
+ return light->SetColor(Unwrap(command.color.value));
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetLightDirectionCmd(
+ Session* session, fuchsia::ui::gfx::SetLightDirectionCmd command) {
+ // TODO(SCN-123): support variables.
+ if (command.direction.variable_id) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplySetLightDirectionCmd(): "
+ "unimplemented: variable direction.";
+ return false;
+ } else if (auto light = session->resources()->FindResource<DirectionalLight>(
+ command.light_id)) {
+ return light->SetDirection(Unwrap(command.direction.value));
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplyAddLightCmd(
+ Session* session, fuchsia::ui::gfx::AddLightCmd command) {
+ if (auto scene =
+ session->resources()->FindResource<Scene>(command.scene_id)) {
+ if (auto light =
+ session->resources()->FindResource<Light>(command.light_id)) {
+ return scene->AddLight(std::move(light));
+ }
+ }
+
+ session->error_reporter()->ERROR() << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplyAddLightCmd(): unimplemented.";
+ return false;
+}
+
+bool GfxCommandApplier::ApplyDetachLightCmd(
+ Session* session, fuchsia::ui::gfx::DetachLightCmd command) {
+ session->error_reporter()->ERROR() << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplyDetachLightCmd(): unimplemented.";
+ return false;
+}
+
+bool GfxCommandApplier::ApplyDetachLightsCmd(
+ Session* session, fuchsia::ui::gfx::DetachLightsCmd command) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplyDetachLightsCmd(): unimplemented.";
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetLabelCmd(
+ Session* session, fuchsia::ui::gfx::SetLabelCmd command) {
+ if (auto r = session->resources()->FindResource<Resource>(command.id)) {
+ return r->SetLabel(command.label);
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplySetDisableClippingCmd(
+ Session* session, fuchsia::ui::gfx::SetDisableClippingCmd command) {
+ if (auto r =
+ session->resources()->FindResource<Renderer>(command.renderer_id)) {
+ r->DisableClipping(command.disable_clipping);
+ return true;
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplyCreateMemory(Session* session, ResourceId id,
+ fuchsia::ui::gfx::MemoryArgs args) {
+ auto memory = CreateMemory(session, id, std::move(args));
+ return memory ? session->resources()->AddResource(id, std::move(memory))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateImage(Session* session, ResourceId id,
+ fuchsia::ui::gfx::ImageArgs args) {
+ if (auto memory =
+ session->resources()->FindResource<Memory>(args.memory_id)) {
+ if (auto image = CreateImage(session, id, std::move(memory), args)) {
+ return session->resources()->AddResource(id, std::move(image));
+ }
+ }
+
+ return false;
+}
+
+bool GfxCommandApplier::ApplyCreateImagePipe(
+ Session* session, ResourceId id, fuchsia::ui::gfx::ImagePipeArgs args) {
+ auto image_pipe = fxl::MakeRefCounted<ImagePipe>(
+ session, id, std::move(args.image_pipe_request),
+ session->session_context().update_scheduler);
+ return session->resources()->AddResource(id, image_pipe);
+}
+
+bool GfxCommandApplier::ApplyCreateBuffer(Session* session, ResourceId id,
+ fuchsia::ui::gfx::BufferArgs args) {
+ if (auto memory =
+ session->resources()->FindResource<Memory>(args.memory_id)) {
+ if (auto buffer = CreateBuffer(session, id, std::move(memory),
+ args.memory_offset, args.num_bytes)) {
+ return session->resources()->AddResource(id, std::move(buffer));
+ }
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplyCreateScene(Session* session, ResourceId id,
+ fuchsia::ui::gfx::SceneArgs args) {
+ auto scene = CreateScene(session, id, std::move(args));
+ return scene ? session->resources()->AddResource(id, std::move(scene))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateCamera(Session* session, ResourceId id,
+ fuchsia::ui::gfx::CameraArgs args) {
+ auto camera = CreateCamera(session, id, std::move(args));
+ return camera ? session->resources()->AddResource(id, std::move(camera))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateStereoCamera(
+ Session* session, ResourceId id, fuchsia::ui::gfx::StereoCameraArgs args) {
+ auto camera = CreateStereoCamera(session, id, args);
+ return camera ? session->resources()->AddResource(id, std::move(camera))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateRenderer(
+ Session* session, ResourceId id, fuchsia::ui::gfx::RendererArgs args) {
+ auto renderer = CreateRenderer(session, id, std::move(args));
+ return renderer ? session->resources()->AddResource(id, std::move(renderer))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateAmbientLight(
+ Session* session, ResourceId id, fuchsia::ui::gfx::AmbientLightArgs args) {
+ auto light = CreateAmbientLight(session, id);
+ return light ? session->resources()->AddResource(id, std::move(light))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateDirectionalLight(
+ Session* session, ResourceId id,
+ fuchsia::ui::gfx::DirectionalLightArgs args) {
+ auto light = CreateDirectionalLight(session, id);
+ return light ? session->resources()->AddResource(id, std::move(light))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateRectangle(
+ Session* session, ResourceId id, fuchsia::ui::gfx::RectangleArgs args) {
+ if (!AssertValueIsOfType(args.width, kFloatValueTypes, session) ||
+ !AssertValueIsOfType(args.height, kFloatValueTypes, session)) {
+ return false;
+ }
+
+ // TODO(SCN-123): support variables.
+ if (IsVariable(args.width) || IsVariable(args.height)) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::ApplyCreateRectangle(): "
+ "unimplemented: variable width/height.";
+ return false;
+ }
+
+ auto rectangle =
+ CreateRectangle(session, id, args.width.vector1(), args.height.vector1());
+ return rectangle ? session->resources()->AddResource(id, std::move(rectangle))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateRoundedRectangle(
+ Session* session, CommandContext* command_context, ResourceId id,
+ fuchsia::ui::gfx::RoundedRectangleArgs args) {
+ if (!AssertValueIsOfType(args.width, kFloatValueTypes, session) ||
+ !AssertValueIsOfType(args.height, kFloatValueTypes, session) ||
+ !AssertValueIsOfType(args.top_left_radius, kFloatValueTypes, session) ||
+ !AssertValueIsOfType(args.top_right_radius, kFloatValueTypes, session) ||
+ !AssertValueIsOfType(args.bottom_left_radius, kFloatValueTypes,
+ session) ||
+ !AssertValueIsOfType(args.bottom_right_radius, kFloatValueTypes,
+ session)) {
+ return false;
+ }
+
+ // TODO(SCN-123): support variables.
+ if (IsVariable(args.width) || IsVariable(args.height) ||
+ IsVariable(args.top_left_radius) || IsVariable(args.top_right_radius) ||
+ IsVariable(args.bottom_left_radius) ||
+ IsVariable(args.bottom_right_radius)) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplyCreateRoundedRectangle(): "
+ "unimplemented: variable width/height/radii.";
+ return false;
+ }
+
+ const float width = args.width.vector1();
+ const float height = args.height.vector1();
+ const float top_left_radius = args.top_left_radius.vector1();
+ const float top_right_radius = args.top_right_radius.vector1();
+ const float bottom_right_radius = args.bottom_right_radius.vector1();
+ const float bottom_left_radius = args.bottom_left_radius.vector1();
+
+ auto rectangle = CreateRoundedRectangle(
+ session, command_context, id, width, height, top_left_radius,
+ top_right_radius, bottom_right_radius, bottom_left_radius);
+ return rectangle ? session->resources()->AddResource(id, std::move(rectangle))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateCircle(Session* session, ResourceId id,
+ fuchsia::ui::gfx::CircleArgs args) {
+ if (!AssertValueIsOfType(args.radius, kFloatValueTypes, session)) {
+ return false;
+ }
+
+ // TODO(SCN-123): support variables.
+ if (IsVariable(args.radius)) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::ApplyCreateCircle(): "
+ "unimplemented: variable radius.";
+ return false;
+ }
+
+ auto circle = CreateCircle(session, id, args.radius.vector1());
+ return circle ? session->resources()->AddResource(id, std::move(circle))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateMesh(Session* session, ResourceId id,
+ fuchsia::ui::gfx::MeshArgs args) {
+ auto mesh = CreateMesh(session, id);
+ return mesh ? session->resources()->AddResource(id, std::move(mesh)) : false;
+}
+
+bool GfxCommandApplier::ApplyCreateMaterial(
+ Session* session, ResourceId id, fuchsia::ui::gfx::MaterialArgs args) {
+ auto material = CreateMaterial(session, id);
+ return material ? session->resources()->AddResource(id, std::move(material))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateView(Session* session, ResourceId id,
+ fuchsia::ui::gfx::ViewArgs args) {
+ // Sanity check. We also rely on FIDL to enforce this for us, although it
+ // does not at the moment.
+ FXL_DCHECK(args.token) << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplyCreateView(): no token provided.";
+
+ if (auto view = CreateView(session, id, std::move(args))) {
+ view->As<View>()->Connect(); // Initiate the link.
+ session->resources()->AddResource(id, std::move(view));
+ return true;
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplyCreateViewHolder(
+ Session* session, ResourceId id, fuchsia::ui::gfx::ViewHolderArgs args) {
+ // Sanity check. We also rely on FIDL to enforce this for us, although it
+ // does not at the moment
+ FXL_DCHECK(args.token)
+ << "scenic_impl::gfx::GfxCommandApplier::ApplyCreateViewHolder()"
+ ": no token provided.";
+
+ if (auto view_holder = CreateViewHolder(session, id, std::move(args))) {
+ view_holder->As<ViewHolder>()->Connect(); // Initiate the link.
+ session->resources()->AddResource(id, std::move(view_holder));
+ return true;
+ }
+ return false;
+}
+
+bool GfxCommandApplier::ApplyCreateClipNode(
+ Session* session, ResourceId id, fuchsia::ui::gfx::ClipNodeArgs args) {
+ auto node = CreateClipNode(session, id, std::move(args));
+ return node ? session->resources()->AddResource(id, std::move(node)) : false;
+}
+
+bool GfxCommandApplier::ApplyCreateEntityNode(
+ Session* session, ResourceId id, fuchsia::ui::gfx::EntityNodeArgs args) {
+ auto node = CreateEntityNode(session, id, std::move(args));
+ return node ? session->resources()->AddResource(id, std::move(node)) : false;
+}
+
+bool GfxCommandApplier::ApplyCreateOpacityNode(
+ Session* session, ResourceId id, fuchsia::ui::gfx::OpacityNodeArgs args) {
+ auto node = CreateOpacityNode(session, id, args);
+ return node ? session->resources()->AddResource(id, std::move(node)) : false;
+}
+
+bool GfxCommandApplier::ApplyCreateShapeNode(
+ Session* session, ResourceId id, fuchsia::ui::gfx::ShapeNodeArgs args) {
+ auto node = CreateShapeNode(session, id, std::move(args));
+ return node ? session->resources()->AddResource(id, std::move(node)) : false;
+}
+
+bool GfxCommandApplier::ApplyCreateCompositor(
+ Session* session, ResourceId id, fuchsia::ui::gfx::CompositorArgs args) {
+ auto compositor = CreateCompositor(session, id, std::move(args));
+ return compositor
+ ? session->resources()->AddResource(id, std::move(compositor))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateDisplayCompositor(
+ Session* session, ResourceId id,
+ fuchsia::ui::gfx::DisplayCompositorArgs args) {
+ auto compositor = CreateDisplayCompositor(session, id, std::move(args));
+ return compositor
+ ? session->resources()->AddResource(id, std::move(compositor))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateImagePipeCompositor(
+ Session* session, ResourceId id,
+ fuchsia::ui::gfx::ImagePipeCompositorArgs args) {
+ auto compositor = CreateImagePipeCompositor(session, id, std::move(args));
+ return compositor
+ ? session->resources()->AddResource(id, std::move(compositor))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateLayerStack(
+ Session* session, ResourceId id, fuchsia::ui::gfx::LayerStackArgs args) {
+ auto layer_stack = CreateLayerStack(session, id, std::move(args));
+ return layer_stack
+ ? session->resources()->AddResource(id, std::move(layer_stack))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateLayer(Session* session, ResourceId id,
+ fuchsia::ui::gfx::LayerArgs args) {
+ auto layer = CreateLayer(session, id, std::move(args));
+ return layer ? session->resources()->AddResource(id, std::move(layer))
+ : false;
+}
+
+bool GfxCommandApplier::ApplyCreateVariable(
+ Session* session, ResourceId id, fuchsia::ui::gfx::VariableArgs args) {
+ auto variable = CreateVariable(session, id, std::move(args));
+ return variable ? session->resources()->AddResource(id, std::move(variable))
+ : false;
+}
+
+ResourcePtr GfxCommandApplier::CreateMemory(Session* session, ResourceId id,
+ fuchsia::ui::gfx::MemoryArgs args) {
+ return Memory::New(session, id, std::move(args), session->error_reporter());
+}
+
+ResourcePtr GfxCommandApplier::CreateImage(Session* session, ResourceId id,
+ MemoryPtr memory,
+ fuchsia::ui::gfx::ImageArgs args) {
+ return Image::New(session, id, memory, args.info, args.memory_offset,
+ session->error_reporter());
+}
+
+ResourcePtr GfxCommandApplier::CreateBuffer(Session* session, ResourceId id,
+ MemoryPtr memory,
+ uint32_t memory_offset,
+ uint32_t num_bytes) {
+ if (memory_offset + num_bytes > memory->size()) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::CreateBuffer(): "
+ "buffer does not fit within memory (buffer "
+ "offset: "
+ << memory_offset << ", buffer size: " << num_bytes
+ << ", memory size: " << memory->size() << ")";
+ return ResourcePtr();
+ }
+
+ // Make a pointer to a subregion of the memory, if necessary.
+ escher::GpuMemPtr gpu_mem =
+ (memory_offset > 0 || num_bytes < memory->size())
+ ? memory->GetGpuMem()->Suballocate(num_bytes, memory_offset)
+ : memory->GetGpuMem();
+
+ return fxl::MakeRefCounted<Buffer>(session, id, std::move(gpu_mem),
+ std::move(memory));
+}
+
+ResourcePtr GfxCommandApplier::CreateScene(Session* session, ResourceId id,
+ fuchsia::ui::gfx::SceneArgs args) {
+ return fxl::MakeRefCounted<Scene>(session, id);
+}
+
+ResourcePtr GfxCommandApplier::CreateCamera(Session* session, ResourceId id,
+ fuchsia::ui::gfx::CameraArgs args) {
+ if (auto scene = session->resources()->FindResource<Scene>(args.scene_id)) {
+ return fxl::MakeRefCounted<Camera>(session, id, std::move(scene));
+ }
+ return ResourcePtr();
+}
+
+ResourcePtr GfxCommandApplier::CreateStereoCamera(
+ Session* session, ResourceId id,
+ const fuchsia::ui::gfx::StereoCameraArgs args) {
+ if (auto scene = session->resources()->FindResource<Scene>(args.scene_id)) {
+ return fxl::MakeRefCounted<StereoCamera>(session, id, std::move(scene));
+ }
+ return ResourcePtr();
+}
+
+ResourcePtr GfxCommandApplier::CreateRenderer(
+ Session* session, ResourceId id, fuchsia::ui::gfx::RendererArgs args) {
+ return fxl::MakeRefCounted<Renderer>(session, id);
+}
+
+ResourcePtr GfxCommandApplier::CreateAmbientLight(Session* session,
+ ResourceId id) {
+ return fxl::MakeRefCounted<AmbientLight>(session, id);
+}
+
+ResourcePtr GfxCommandApplier::CreateDirectionalLight(Session* session,
+ ResourceId id) {
+ return fxl::MakeRefCounted<DirectionalLight>(session, id);
+}
+
+ResourcePtr GfxCommandApplier::CreateView(Session* session, ResourceId id,
+ fuchsia::ui::gfx::ViewArgs args) {
+ ViewLinker* view_linker = session->session_context().view_linker;
+ ViewLinker::ImportLink link = view_linker->CreateImport(
+ std::move(args.token), session->error_reporter());
+
+ // Create a View if the Link was successfully registered.
+ if (link.valid()) {
+ return fxl::MakeRefCounted<View>(session, id, std::move(link));
+ }
+ return nullptr;
+}
+
+ResourcePtr GfxCommandApplier::CreateViewHolder(
+ Session* session, ResourceId id, fuchsia::ui::gfx::ViewHolderArgs args) {
+ ViewLinker* view_linker = session->session_context().view_linker;
+ ViewLinker::ExportLink link = view_linker->CreateExport(
+ std::move(args.token), session->error_reporter());
+
+ // Create a ViewHolder if the Link was successfully registered.
+ if (link.valid()) {
+ return fxl::MakeRefCounted<ViewHolder>(session, id, std::move(link));
+ }
+ return nullptr;
+}
+
+ResourcePtr GfxCommandApplier::CreateClipNode(
+ Session* session, ResourceId id, fuchsia::ui::gfx::ClipNodeArgs args) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::CreateClipNode(): "
+ "unimplemented.";
+ return ResourcePtr();
+}
+
+ResourcePtr GfxCommandApplier::CreateEntityNode(
+ Session* session, ResourceId id, fuchsia::ui::gfx::EntityNodeArgs args) {
+ return fxl::MakeRefCounted<EntityNode>(session, id);
+}
+
+ResourcePtr GfxCommandApplier::CreateOpacityNode(
+ Session* session, ResourceId id, fuchsia::ui::gfx::OpacityNodeArgs args) {
+ return fxl::MakeRefCounted<OpacityNode>(session, id);
+}
+
+ResourcePtr GfxCommandApplier::CreateShapeNode(
+ Session* session, ResourceId id, fuchsia::ui::gfx::ShapeNodeArgs args) {
+ return fxl::MakeRefCounted<ShapeNode>(session, id);
+}
+
+ResourcePtr GfxCommandApplier::CreateCompositor(
+ Session* session, ResourceId id, fuchsia::ui::gfx::CompositorArgs args) {
+ return Compositor::New(session, id, session->session_context().scene_graph);
+}
+
+ResourcePtr GfxCommandApplier::CreateDisplayCompositor(
+ Session* session, ResourceId id,
+ fuchsia::ui::gfx::DisplayCompositorArgs args) {
+ Display* display =
+ session->session_context().display_manager->default_display();
+ if (!display) {
+ session->error_reporter()->ERROR()
+ << "There is no default display available.";
+ return nullptr;
+ }
+
+ if (display->is_claimed()) {
+ session->error_reporter()->ERROR()
+ << "The default display has already been claimed "
+ "by another compositor.";
+ return nullptr;
+ }
+
+ return fxl::AdoptRef(new DisplayCompositor(
+ session, id, session->session_context().scene_graph, display,
+ SwapchainFactory::CreateDisplaySwapchain(
+ display, session->session_context().display_manager,
+ session->session_context().event_timestamper,
+ session->session_context().escher)));
+}
+
+ResourcePtr GfxCommandApplier::CreateImagePipeCompositor(
+ Session* session, ResourceId id,
+ fuchsia::ui::gfx::ImagePipeCompositorArgs args) {
+ // TODO(SCN-179)
+ session->error_reporter()->ERROR() << "scenic_impl::gfx::GfxCommandApplier::"
+ "ApplyCreateImagePipeCompositor() "
+ "is unimplemented (SCN-179)";
+ return ResourcePtr();
+}
+
+ResourcePtr GfxCommandApplier::CreateLayerStack(
+ Session* session, ResourceId id, fuchsia::ui::gfx::LayerStackArgs args) {
+ return fxl::MakeRefCounted<LayerStack>(session, id);
+}
+
+ResourcePtr GfxCommandApplier::CreateVariable(
+ Session* session, ResourceId id, fuchsia::ui::gfx::VariableArgs args) {
+ fxl::RefPtr<Variable> variable;
+ switch (args.type) {
+ case fuchsia::ui::gfx::ValueType::kVector1:
+ variable = fxl::MakeRefCounted<FloatVariable>(session, id);
+ break;
+ case fuchsia::ui::gfx::ValueType::kVector2:
+ variable = fxl::MakeRefCounted<Vector2Variable>(session, id);
+ break;
+ case fuchsia::ui::gfx::ValueType::kVector3:
+ variable = fxl::MakeRefCounted<Vector3Variable>(session, id);
+ break;
+ case fuchsia::ui::gfx::ValueType::kVector4:
+ variable = fxl::MakeRefCounted<Vector4Variable>(session, id);
+ break;
+ case fuchsia::ui::gfx::ValueType::kMatrix4:
+ variable = fxl::MakeRefCounted<Matrix4x4Variable>(session, id);
+ break;
+ case fuchsia::ui::gfx::ValueType::kColorRgb:
+ // not yet supported
+ variable = nullptr;
+ break;
+ case fuchsia::ui::gfx::ValueType::kColorRgba:
+ // not yet supported
+ variable = nullptr;
+ break;
+ case fuchsia::ui::gfx::ValueType::kQuaternion:
+ variable = fxl::MakeRefCounted<QuaternionVariable>(session, id);
+ break;
+ case fuchsia::ui::gfx::ValueType::kFactoredTransform:
+ /* variable = fxl::MakeRefCounted<TransformVariable>(session, id); */
+ variable = nullptr;
+ break;
+ case fuchsia::ui::gfx::ValueType::kNone:
+ break;
+ }
+ if (variable && variable->SetValue(args.initial_value)) {
+ return variable;
+ }
+ return nullptr;
+}
+
+ResourcePtr GfxCommandApplier::CreateLayer(Session* session, ResourceId id,
+ fuchsia::ui::gfx::LayerArgs args) {
+ return fxl::MakeRefCounted<Layer>(session, id);
+}
+
+ResourcePtr GfxCommandApplier::CreateCircle(Session* session, ResourceId id,
+ float initial_radius) {
+ return fxl::MakeRefCounted<CircleShape>(session, id, initial_radius);
+}
+
+ResourcePtr GfxCommandApplier::CreateRectangle(Session* session, ResourceId id,
+ float width, float height) {
+ return fxl::MakeRefCounted<RectangleShape>(session, id, width, height);
+}
+
+ResourcePtr GfxCommandApplier::CreateRoundedRectangle(
+ Session* session, CommandContext* command_context, ResourceId id,
+ float width, float height, float top_left_radius, float top_right_radius,
+ float bottom_right_radius, float bottom_left_radius) {
+ auto factory = session->session_context().escher_rounded_rect_factory;
+ if (!factory) {
+ session->error_reporter()->ERROR()
+ << "scenic_impl::gfx::GfxCommandApplier::CreateRoundedRectangle(): "
+ "no RoundedRectFactory available.";
+ return ResourcePtr();
+ }
+
+ // If radii sum exceeds width or height, scale them down.
+ float top_radii_sum = top_left_radius + top_right_radius;
+ float top_scale = std::min(width / top_radii_sum, 1.f);
+
+ float bottom_radii_sum = bottom_left_radius + bottom_right_radius;
+ float bottom_scale = std::min(width / bottom_radii_sum, 1.f);
+
+ float left_radii_sum = top_left_radius + bottom_left_radius;
+ float left_scale = std::min(height / left_radii_sum, 1.f);
+
+ float right_radii_sum = top_right_radius + bottom_right_radius;
+ float right_scale = std::min(height / right_radii_sum, 1.f);
+
+ top_left_radius *= std::min(top_scale, left_scale);
+ top_right_radius *= std::min(top_scale, right_scale);
+ bottom_left_radius *= std::min(bottom_scale, left_scale);
+ bottom_right_radius *= std::min(bottom_scale, right_scale);
+
+ escher::RoundedRectSpec rect_spec(width, height, top_left_radius,
+ top_right_radius, bottom_right_radius,
+ bottom_left_radius);
+ escher::MeshSpec mesh_spec{escher::MeshAttribute::kPosition2D |
+ escher::MeshAttribute::kUV};
+
+ return fxl::MakeRefCounted<RoundedRectangleShape>(
+ session, id, rect_spec,
+ factory->NewRoundedRect(rect_spec, mesh_spec,
+ command_context->batch_gpu_uploader()));
+}
+
+ResourcePtr GfxCommandApplier::CreateMesh(Session* session, ResourceId id) {
+ return fxl::MakeRefCounted<MeshShape>(session, id);
+}
+
+ResourcePtr GfxCommandApplier::CreateMaterial(Session* session, ResourceId id) {
+ return fxl::MakeRefCounted<Material>(session, id);
+}
+
+} // namespace gfx
+} // namespace scenic_impl
diff --git a/lib/ui/gfx/engine/gfx_command_applier.h b/lib/ui/gfx/engine/gfx_command_applier.h
new file mode 100644
index 0000000..a3cdfed
--- /dev/null
+++ b/lib/ui/gfx/engine/gfx_command_applier.h
@@ -0,0 +1,281 @@
+// Copyright 2019 The Fuchsia 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 GARNET_LIB_UI_GFX_ENGINE_GFX_COMMAND_APPLIER_H_
+#define GARNET_LIB_UI_GFX_ENGINE_GFX_COMMAND_APPLIER_H_
+
+#include "garnet/lib/ui/gfx/engine/resource_map.h"
+#include "garnet/lib/ui/gfx/engine/session_context.h"
+#include "garnet/lib/ui/gfx/id.h"
+#include "garnet/lib/ui/gfx/resources/import.h"
+#include "garnet/lib/ui/gfx/resources/memory.h"
+#include "garnet/lib/ui/gfx/resources/resource.h"
+#include "garnet/lib/ui/gfx/resources/resource_context.h"
+#include "garnet/lib/ui/scenic/event_reporter.h"
+#include "garnet/lib/ui/scenic/util/error_reporter.h"
+#include "garnet/lib/ui/scenic/util/print_command.h"
+#include "lib/escher/flib/fence_set_listener.h"
+#include "lib/fxl/memory/weak_ptr.h"
+#include "lib/fxl/tasks/task_runner.h"
+
+namespace scenic_impl {
+namespace gfx {
+
+class Image;
+using ImagePtr = fxl::RefPtr<Image>;
+
+class ImageBase;
+using ImageBasePtr = fxl::RefPtr<ImageBase>;
+
+class ImagePipe;
+using ImagePipePtr = fxl::RefPtr<ImagePipe>;
+
+class CommandContext;
+class Session;
+
+// Responsible for applying gfx commands to sessions.
+// Does not own any state. The session to be modified is instead
+// passed in as an argument to ApplyCommand.
+class GfxCommandApplier {
+ public:
+ // Apply the operation to the current session state. Return true if
+ // successful, and false if the op is somehow invalid. In the latter case,
+ // the Session is left unchanged.
+ static bool ApplyCommand(Session* session, CommandContext* command_context,
+ fuchsia::ui::gfx::Command command);
+
+ private:
+ // Return false and logs an error to the session's ErrorReporter if the value
+ // is not of the expected type.
+ // NOTE: although failure does not halt execution of the program,
+ // it does indicate client error, and will be used by the caller
+ // to tear down the Session.
+ static bool AssertValueIsOfType(const fuchsia::ui::gfx::Value& value,
+ const fuchsia::ui::gfx::Value::Tag* tags,
+ size_t tag_count, Session* session);
+ template <size_t N>
+ static bool AssertValueIsOfType(
+ const fuchsia::ui::gfx::Value& value,
+ const std::array<fuchsia::ui::gfx::Value::Tag, N>& tags,
+ Session* session) {
+ return AssertValueIsOfType(value, tags.data(), N, session);
+ }
+
+ // Functions for applying specific Commands. Called by ApplyCommand().
+ static bool ApplyCreateResourceCmd(
+ Session* session, CommandContext* command_context,
+ fuchsia::ui::gfx::CreateResourceCmd command);
+ static bool ApplyReleaseResourceCmd(
+ Session* session, fuchsia::ui::gfx::ReleaseResourceCmd command);
+ static bool ApplyExportResourceCmd(
+ Session* session, fuchsia::ui::gfx::ExportResourceCmd command);
+ static bool ApplyImportResourceCmd(
+ Session* session, fuchsia::ui::gfx::ImportResourceCmd command);
+ static bool ApplyAddChildCmd(Session* session,
+ fuchsia::ui::gfx::AddChildCmd command);
+ static bool ApplyAddPartCmd(Session* session,
+ fuchsia::ui::gfx::AddPartCmd command);
+ static bool ApplyDetachCmd(Session* session,
+ fuchsia::ui::gfx::DetachCmd command);
+ static bool ApplyDetachChildrenCmd(
+ Session* session, fuchsia::ui::gfx::DetachChildrenCmd command);
+ static bool ApplySetTagCmd(Session* session,
+ fuchsia::ui::gfx::SetTagCmd command);
+ static bool ApplySetTranslationCmd(
+ Session* session, fuchsia::ui::gfx::SetTranslationCmd command);
+ static bool ApplySetScaleCmd(Session* session,
+ fuchsia::ui::gfx::SetScaleCmd command);
+ static bool ApplySetRotationCmd(Session* session,
+ fuchsia::ui::gfx::SetRotationCmd command);
+ static bool ApplySetAnchorCmd(Session* session,
+ fuchsia::ui::gfx::SetAnchorCmd command);
+ static bool ApplySetSizeCmd(Session* session,
+ fuchsia::ui::gfx::SetSizeCmd command);
+ static bool ApplySetOpacityCmd(Session* session,
+ fuchsia::ui::gfx::SetOpacityCmd command);
+ static bool ApplySendSizeChangeHintCmd(
+ Session* session, fuchsia::ui::gfx::SendSizeChangeHintCmdHACK command);
+ static bool ApplySetShapeCmd(Session* session,
+ fuchsia::ui::gfx::SetShapeCmd command);
+ static bool ApplySetMaterialCmd(Session* session,
+ fuchsia::ui::gfx::SetMaterialCmd command);
+ static bool ApplySetClipCmd(Session* session,
+ fuchsia::ui::gfx::SetClipCmd command);
+ static bool ApplySetViewPropertiesCmd(
+ Session* session, fuchsia::ui::gfx::SetViewPropertiesCmd command);
+ static bool ApplySetHitTestBehaviorCmd(
+ Session* session, fuchsia::ui::gfx::SetHitTestBehaviorCmd command);
+ static bool ApplySetCameraCmd(Session* session,
+ fuchsia::ui::gfx::SetCameraCmd command);
+ static bool ApplySetCameraTransformCmd(
+ Session* session, fuchsia::ui::gfx::SetCameraTransformCmd command);
+ static bool ApplySetCameraProjectionCmd(
+ Session* session, fuchsia::ui::gfx::SetCameraProjectionCmd command);
+ static bool ApplySetStereoCameraProjectionCmd(
+ Session* session, fuchsia::ui::gfx::SetStereoCameraProjectionCmd command);
+ static bool ApplySetCameraPoseBufferCmd(
+ Session* session, fuchsia::ui::gfx::SetCameraPoseBufferCmd command);
+ static bool ApplySetLightColorCmd(Session* session,
+ fuchsia::ui::gfx::SetLightColorCmd command);
+ static bool ApplySetLightDirectionCmd(
+ Session* session, fuchsia::ui::gfx::SetLightDirectionCmd command);
+ static bool ApplyAddLightCmd(Session* session,
+ fuchsia::ui::gfx::AddLightCmd command);
+ static bool ApplyDetachLightCmd(Session* session,
+ fuchsia::ui::gfx::DetachLightCmd command);
+ static bool ApplyDetachLightsCmd(Session* session,
+ fuchsia::ui::gfx::DetachLightsCmd command);
+ static bool ApplySetTextureCmd(Session* session,
+ fuchsia::ui::gfx::SetTextureCmd command);
+ static bool ApplySetColorCmd(Session* session,
+ fuchsia::ui::gfx::SetColorCmd command);
+ static bool ApplyBindMeshBuffersCmd(
+ Session* session, fuchsia::ui::gfx::BindMeshBuffersCmd command);
+ static bool ApplyAddLayerCmd(Session* session,
+ fuchsia::ui::gfx::AddLayerCmd command);
+ static bool ApplyRemoveLayerCmd(Session* session,
+ fuchsia::ui::gfx::RemoveLayerCmd command);
+ static bool ApplyRemoveAllLayersCmd(
+ Session* session, fuchsia::ui::gfx::RemoveAllLayersCmd command);
+ static bool ApplySetLayerStackCmd(Session* session,
+ fuchsia::ui::gfx::SetLayerStackCmd command);
+ static bool ApplySetRendererCmd(Session* session,
+ fuchsia::ui::gfx::SetRendererCmd command);
+ static bool ApplySetRendererParamCmd(
+ Session* session, fuchsia::ui::gfx::SetRendererParamCmd command);
+ static bool ApplySetEventMaskCmd(Session* session,
+ fuchsia::ui::gfx::SetEventMaskCmd command);
+ static bool ApplySetLabelCmd(Session* session,
+ fuchsia::ui::gfx::SetLabelCmd command);
+ static bool ApplySetDisableClippingCmd(
+ Session* session, fuchsia::ui::gfx::SetDisableClippingCmd command);
+
+ // Resource creation functions, called by ApplyCreateResourceCmd(Session*
+ // session, ).
+ static bool ApplyCreateMemory(Session* session, ResourceId id,
+ fuchsia::ui::gfx::MemoryArgs args);
+ static bool ApplyCreateImage(Session* session, ResourceId id,
+ fuchsia::ui::gfx::ImageArgs args);
+ static bool ApplyCreateImagePipe(Session* session, ResourceId id,
+ fuchsia::ui::gfx::ImagePipeArgs args);
+ static bool ApplyCreateBuffer(Session* session, ResourceId id,
+ fuchsia::ui::gfx::BufferArgs args);
+ static bool ApplyCreateScene(Session* session, ResourceId id,
+ fuchsia::ui::gfx::SceneArgs args);
+ static bool ApplyCreateCamera(Session* session, ResourceId id,
+ fuchsia::ui::gfx::CameraArgs args);
+ static bool ApplyCreateStereoCamera(Session* session, ResourceId id,
+ fuchsia::ui::gfx::StereoCameraArgs args);
+ static bool ApplyCreateRenderer(Session* session, ResourceId id,
+ fuchsia::ui::gfx::RendererArgs args);
+ static bool ApplyCreateAmbientLight(Session* session, ResourceId id,
+ fuchsia::ui::gfx::AmbientLightArgs args);
+ static bool ApplyCreateDirectionalLight(
+ Session* session, ResourceId id,
+ fuchsia::ui::gfx::DirectionalLightArgs args);
+ static bool ApplyCreateRectangle(Session* session, ResourceId id,
+ fuchsia::ui::gfx::RectangleArgs args);
+ static bool ApplyCreateRoundedRectangle(
+ Session* session, CommandContext* command_context, ResourceId id,
+ fuchsia::ui::gfx::RoundedRectangleArgs args);
+ static bool ApplyCreateCircle(Session* session, ResourceId id,
+ fuchsia::ui::gfx::CircleArgs args);
+ static bool ApplyCreateMesh(Session* session, ResourceId id,
+ fuchsia::ui::gfx::MeshArgs args);
+ static bool ApplyCreateMaterial(Session* session, ResourceId id,
+ fuchsia::ui::gfx::MaterialArgs args);
+ static bool ApplyCreateView(Session* session, ResourceId id,
+ fuchsia::ui::gfx::ViewArgs args);
+ static bool ApplyCreateViewHolder(Session* session, ResourceId id,
+ fuchsia::ui::gfx::ViewHolderArgs args);
+ static bool ApplyCreateClipNode(Session* session, ResourceId id,
+ fuchsia::ui::gfx::ClipNodeArgs args);
+ static bool ApplyCreateEntityNode(Session* session, ResourceId id,
+ fuchsia::ui::gfx::EntityNodeArgs args);
+ static bool ApplyCreateOpacityNode(Session* session, ResourceId id,
+ fuchsia::ui::gfx::OpacityNodeArgs args);
+ static bool ApplyCreateShapeNode(Session* session, ResourceId id,
+ fuchsia::ui::gfx::ShapeNodeArgs args);
+ static bool ApplyCreateCompositor(Session* session, ResourceId id,
+ fuchsia::ui::gfx::CompositorArgs args);
+ static bool ApplyCreateDisplayCompositor(
+ Session* session, ResourceId id,
+ fuchsia::ui::gfx::DisplayCompositorArgs args);
+ static bool ApplyCreateImagePipeCompositor(
+ Session* session, ResourceId id,
+ fuchsia::ui::gfx::ImagePipeCompositorArgs args);
+ static bool ApplyCreateLayerStack(Session* session, ResourceId id,
+ fuchsia::ui::gfx::LayerStackArgs args);
+ static bool ApplyCreateLayer(Session* session, ResourceId id,
+ fuchsia::ui::gfx::LayerArgs args);
+ static bool ApplyCreateVariable(Session* session, ResourceId id,
+ fuchsia::ui::gfx::VariableArgs args);
+ static bool ApplyTakeSnapshotCmdHACK(
+ Session* session, fuchsia::ui::gfx::TakeSnapshotCmdHACK command);
+
+ // Actually create resources.
+ static ResourcePtr CreateMemory(Session* session, ResourceId id,
+ fuchsia::ui::gfx::MemoryArgs args);
+ static ResourcePtr CreateImage(Session* session, ResourceId id,
+ MemoryPtr memory,
+ fuchsia::ui::gfx::ImageArgs args);
+ static ResourcePtr CreateBuffer(Session* session, ResourceId id,
+ MemoryPtr memory, uint32_t memory_offset,
+ uint32_t num_bytes);
+
+ static ResourcePtr CreateScene(Session* session, ResourceId id,
+ fuchsia::ui::gfx::SceneArgs args);
+ static ResourcePtr CreateCamera(Session* session, ResourceId id,
+ fuchsia::ui::gfx::CameraArgs args);
+ static ResourcePtr CreateStereoCamera(
+ Session* session, ResourceId id, fuchsia::ui::gfx::StereoCameraArgs args);
+ static ResourcePtr CreateRenderer(Session* session, ResourceId id,
+ fuchsia::ui::gfx::RendererArgs args);
+
+ static ResourcePtr CreateAmbientLight(Session* session, ResourceId id);
+ static ResourcePtr CreateDirectionalLight(Session* session, ResourceId id);
+
+ static ResourcePtr CreateView(Session* session, ResourceId id,
+ fuchsia::ui::gfx::ViewArgs args);
+ static ResourcePtr CreateViewHolder(Session* session, ResourceId id,
+ fuchsia::ui::gfx::ViewHolderArgs args);
+ static ResourcePtr CreateClipNode(Session* session, ResourceId id,
+ fuchsia::ui::gfx::ClipNodeArgs args);
+ static ResourcePtr CreateEntityNode(Session* session, ResourceId id,
+ fuchsia::ui::gfx::EntityNodeArgs args);
+ static ResourcePtr CreateOpacityNode(Session* session, ResourceId id,
+ fuchsia::ui::gfx::OpacityNodeArgs args);
+ static ResourcePtr CreateShapeNode(Session* session, ResourceId id,
+ fuchsia::ui::gfx::ShapeNodeArgs args);
+
+ static ResourcePtr CreateCompositor(Session* session, ResourceId id,
+ fuchsia::ui::gfx::CompositorArgs args);
+ static ResourcePtr CreateDisplayCompositor(
+ Session* session, ResourceId id,
+ fuchsia::ui::gfx::DisplayCompositorArgs args);
+ static ResourcePtr CreateImagePipeCompositor(
+ Session* session, ResourceId id,
+ fuchsia::ui::gfx::ImagePipeCompositorArgs args);
+ static ResourcePtr CreateLayerStack(Session* session, ResourceId id,
+ fuchsia::ui::gfx::LayerStackArgs args);
+ static ResourcePtr CreateLayer(Session* session, ResourceId id,
+ fuchsia::ui::gfx::LayerArgs args);
+ static ResourcePtr CreateCircle(Session* session, ResourceId id,
+ float initial_radius);
+ static ResourcePtr CreateRectangle(Session* session, ResourceId id,
+ float width, float height);
+ static ResourcePtr CreateRoundedRectangle(
+ Session* session, CommandContext* command_context, ResourceId id,
+ float width, float height, float top_left_radius, float top_right_radius,
+ float bottom_right_radius, float bottom_left_radius);
+ static ResourcePtr CreateMesh(Session* session, ResourceId id);
+ static ResourcePtr CreateMaterial(Session* session, ResourceId id);
+ static ResourcePtr CreateVariable(Session* session, ResourceId id,
+ fuchsia::ui::gfx::VariableArgs args);
+};
+
+} // namespace gfx
+} // namespace scenic_impl
+
+#endif // GARNET_LIB_UI_GFX_ENGINE_GFX_COMMAND_APPLIER_H_
diff --git a/lib/ui/gfx/engine/session.cc b/lib/ui/gfx/engine/session.cc
index 6db1eef..02db4d8 100644
--- a/lib/ui/gfx/engine/session.cc
+++ b/lib/ui/gfx/engine/session.cc
@@ -11,34 +11,11 @@
#include <lib/async/default.h>
#include <trace/event.h>
+#include "garnet/lib/ui/gfx/engine/gfx_command_applier.h"
#include "garnet/lib/ui/gfx/engine/hit_tester.h"
#include "garnet/lib/ui/gfx/engine/session_handler.h"
-#include "garnet/lib/ui/gfx/resources/buffer.h"
-#include "garnet/lib/ui/gfx/resources/camera.h"
-#include "garnet/lib/ui/gfx/resources/compositor/display_compositor.h"
-#include "garnet/lib/ui/gfx/resources/compositor/layer.h"
#include "garnet/lib/ui/gfx/resources/compositor/layer_stack.h"
-#include "garnet/lib/ui/gfx/resources/image.h"
#include "garnet/lib/ui/gfx/resources/image_pipe.h"
-#include "garnet/lib/ui/gfx/resources/image_pipe_handler.h"
-#include "garnet/lib/ui/gfx/resources/lights/ambient_light.h"
-#include "garnet/lib/ui/gfx/resources/lights/directional_light.h"
-#include "garnet/lib/ui/gfx/resources/memory.h"
-#include "garnet/lib/ui/gfx/resources/nodes/entity_node.h"
-#include "garnet/lib/ui/gfx/resources/nodes/node.h"
-#include "garnet/lib/ui/gfx/resources/nodes/opacity_node.h"
-#include "garnet/lib/ui/gfx/resources/nodes/scene.h"
-#include "garnet/lib/ui/gfx/resources/nodes/shape_node.h"
-#include "garnet/lib/ui/gfx/resources/renderers/renderer.h"
-#include "garnet/lib/ui/gfx/resources/shapes/circle_shape.h"
-#include "garnet/lib/ui/gfx/resources/shapes/mesh_shape.h"
-#include "garnet/lib/ui/gfx/resources/shapes/rectangle_shape.h"
-#include "garnet/lib/ui/gfx/resources/shapes/rounded_rectangle_shape.h"
-#include "garnet/lib/ui/gfx/resources/snapshot/snapshotter.h"
-#include "garnet/lib/ui/gfx/resources/stereo_camera.h"
-#include "garnet/lib/ui/gfx/resources/variable.h"
-#include "garnet/lib/ui/gfx/resources/view.h"
-#include "garnet/lib/ui/gfx/resources/view_holder.h"
#include "garnet/lib/ui/gfx/swapchain/swapchain_factory.h"
#include "garnet/lib/ui/gfx/util/time.h"
#include "garnet/lib/ui/gfx/util/unwrap.h"
@@ -55,14 +32,6 @@
namespace {
-// Makes it convenient to check that a value is constant and of a specific type,
-// or a variable.
-// TODO: There should also be a convenient way of type-checking a variable;
-// this will necessarily involve looking up the value in the ResourceMap.
-constexpr std::array<::fuchsia::ui::gfx::Value::Tag, 2> kFloatValueTypes{
- {::fuchsia::ui::gfx::Value::Tag::kVector1,
- ::fuchsia::ui::gfx::Value::Tag::kVariableId}};
-
// Converts the provided vector of Hits into a fidl array of HitPtrs.
fidl::VectorPtr<::fuchsia::ui::gfx::Hit> WrapHits(
const std::vector<Hit>& hits) {
@@ -96,1332 +65,19 @@
session_context_.escher_resource_recycler,
session_context_.escher_image_factory,
session_context_.escher_gpu_uploader}),
- resources_(error_reporter),
+ resources_(error_reporter_),
weak_factory_(this) {
FXL_DCHECK(error_reporter);
}
-Session::~Session() { FXL_DCHECK(!is_valid_); }
-
-bool Session::ApplyCommand(CommandContext* command_context,
- ::fuchsia::ui::gfx::Command command) {
- TRACE_DURATION("gfx", "Session::ApplyCommand");
- switch (command.Which()) {
- case ::fuchsia::ui::gfx::Command::Tag::kCreateResource:
- return ApplyCreateResourceCmd(command_context,
- std::move(command.create_resource()));
- case ::fuchsia::ui::gfx::Command::Tag::kReleaseResource:
- return ApplyReleaseResourceCmd(std::move(command.release_resource()));
- case ::fuchsia::ui::gfx::Command::Tag::kExportResource:
- return ApplyExportResourceCmd(std::move(command.export_resource()));
- case ::fuchsia::ui::gfx::Command::Tag::kImportResource:
- return ApplyImportResourceCmd(std::move(command.import_resource()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetImportFocus: {
- // TODO(SCN-1026): Remove this.
- if (auto import = resources_.FindResource<Import>(
- command.set_import_focus().id,
- ResourceMap::ErrorBehavior::kDontReportErrors)) {
- import->set_focusable(command.set_import_focus().focusable);
- return true;
- }
- return false;
- }
- case ::fuchsia::ui::gfx::Command::Tag::kAddChild:
- return ApplyAddChildCmd(std::move(command.add_child()));
- case ::fuchsia::ui::gfx::Command::Tag::kAddPart:
- return ApplyAddPartCmd(std::move(command.add_part()));
- case ::fuchsia::ui::gfx::Command::Tag::kDetach:
- return ApplyDetachCmd(std::move(command.detach()));
- case ::fuchsia::ui::gfx::Command::Tag::kDetachChildren:
- return ApplyDetachChildrenCmd(std::move(command.detach_children()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetTag:
- return ApplySetTagCmd(std::move(command.set_tag()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetTranslation:
- return ApplySetTranslationCmd(std::move(command.set_translation()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetScale:
- return ApplySetScaleCmd(std::move(command.set_scale()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetRotation:
- return ApplySetRotationCmd(std::move(command.set_rotation()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetAnchor:
- return ApplySetAnchorCmd(std::move(command.set_anchor()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetSize:
- return ApplySetSizeCmd(std::move(command.set_size()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetOpacity:
- return ApplySetOpacityCmd(command.set_opacity());
- case ::fuchsia::ui::gfx::Command::Tag::kSendSizeChangeHintHack:
- return ApplySendSizeChangeHintCmd(command.send_size_change_hint_hack());
- case ::fuchsia::ui::gfx::Command::Tag::kSetShape:
- return ApplySetShapeCmd(std::move(command.set_shape()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetMaterial:
- return ApplySetMaterialCmd(std::move(command.set_material()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetClip:
- return ApplySetClipCmd(std::move(command.set_clip()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetHitTestBehavior:
- return ApplySetHitTestBehaviorCmd(
- std::move(command.set_hit_test_behavior()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetViewProperties:
- return ApplySetViewPropertiesCmd(
- std::move(command.set_view_properties()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetCamera:
- return ApplySetCameraCmd(std::move(command.set_camera()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetCameraTransform:
- return ApplySetCameraTransformCmd(
- std::move(command.set_camera_transform()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetCameraProjection:
- return ApplySetCameraProjectionCmd(
- std::move(command.set_camera_projection()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetStereoCameraProjection:
- return ApplySetStereoCameraProjectionCmd(
- std::move(command.set_stereo_camera_projection()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetCameraPoseBuffer:
- return ApplySetCameraPoseBufferCmd(
- std::move(command.set_camera_pose_buffer()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetLightColor:
- return ApplySetLightColorCmd(std::move(command.set_light_color()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetLightDirection:
- return ApplySetLightDirectionCmd(
- std::move(command.set_light_direction()));
- case ::fuchsia::ui::gfx::Command::Tag::kAddLight:
- return ApplyAddLightCmd(std::move(command.add_light()));
- case ::fuchsia::ui::gfx::Command::Tag::kDetachLight:
- return ApplyDetachLightCmd(std::move(command.detach_light()));
- case ::fuchsia::ui::gfx::Command::Tag::kDetachLights:
- return ApplyDetachLightsCmd(std::move(command.detach_lights()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetTexture:
- return ApplySetTextureCmd(std::move(command.set_texture()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetColor:
- return ApplySetColorCmd(std::move(command.set_color()));
- case ::fuchsia::ui::gfx::Command::Tag::kBindMeshBuffers:
- return ApplyBindMeshBuffersCmd(std::move(command.bind_mesh_buffers()));
- case ::fuchsia::ui::gfx::Command::Tag::kAddLayer:
- return ApplyAddLayerCmd(std::move(command.add_layer()));
- case ::fuchsia::ui::gfx::Command::Tag::kRemoveLayer:
- return ApplyRemoveLayerCmd(std::move(command.remove_layer()));
- case ::fuchsia::ui::gfx::Command::Tag::kRemoveAllLayers:
- return ApplyRemoveAllLayersCmd(std::move(command.remove_all_layers()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetLayerStack:
- return ApplySetLayerStackCmd(std::move(command.set_layer_stack()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetRenderer:
- return ApplySetRendererCmd(std::move(command.set_renderer()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetRendererParam:
- return ApplySetRendererParamCmd(std::move(command.set_renderer_param()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetEventMask:
- return ApplySetEventMaskCmd(std::move(command.set_event_mask()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetLabel:
- return ApplySetLabelCmd(std::move(command.set_label()));
- case ::fuchsia::ui::gfx::Command::Tag::kSetDisableClipping:
- return ApplySetDisableClippingCmd(
- std::move(command.set_disable_clipping()));
- case ::fuchsia::ui::gfx::Command::Tag::kTakeSnapshotCmd:
- return ApplyTakeSnapshotCmdHACK(std::move(command.take_snapshot_cmd()));
- case ::fuchsia::ui::gfx::Command::Tag::Invalid:
- // FIDL validation should make this impossible.
- FXL_CHECK(false);
- return false;
- }
-}
-
-bool Session::ApplyCreateResourceCmd(
- CommandContext* command_context,
- ::fuchsia::ui::gfx::CreateResourceCmd command) {
- const ResourceId id = command.id;
- if (id == 0) {
- using ::operator<<; // From print_commands.h
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplyCreateResourceCmd(): invalid ID: "
- << command;
- return false;
- }
-
- switch (command.resource.Which()) {
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kMemory:
- return ApplyCreateMemory(id, std::move(command.resource.memory()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kImage:
- return ApplyCreateImage(id, std::move(command.resource.image()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kImagePipe:
- return ApplyCreateImagePipe(id, std::move(command.resource.image_pipe()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kBuffer:
- return ApplyCreateBuffer(id, std::move(command.resource.buffer()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kScene:
- return ApplyCreateScene(id, std::move(command.resource.scene()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kCamera:
- return ApplyCreateCamera(id, std::move(command.resource.camera()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kStereoCamera:
- return ApplyCreateStereoCamera(
- id, std::move(command.resource.stereo_camera()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kRenderer:
- return ApplyCreateRenderer(id, std::move(command.resource.renderer()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kAmbientLight:
- return ApplyCreateAmbientLight(
- id, std::move(command.resource.ambient_light()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kDirectionalLight:
- return ApplyCreateDirectionalLight(
- id, std::move(command.resource.directional_light()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kRectangle:
- return ApplyCreateRectangle(id, std::move(command.resource.rectangle()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kRoundedRectangle:
- return ApplyCreateRoundedRectangle(
- command_context, id, std::move(command.resource.rounded_rectangle()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kCircle:
- return ApplyCreateCircle(id, std::move(command.resource.circle()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kMesh:
- return ApplyCreateMesh(id, std::move(command.resource.mesh()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kMaterial:
- return ApplyCreateMaterial(id, std::move(command.resource.material()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kView:
- return ApplyCreateView(id, std::move(command.resource.view()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kViewHolder:
- return ApplyCreateViewHolder(id,
- std::move(command.resource.view_holder()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kClipNode:
- return ApplyCreateClipNode(id, std::move(command.resource.clip_node()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kOpacityNode:
- return ApplyCreateOpacityNode(id, command.resource.opacity_node());
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kEntityNode:
- return ApplyCreateEntityNode(id,
- std::move(command.resource.entity_node()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kShapeNode:
- return ApplyCreateShapeNode(id, std::move(command.resource.shape_node()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kCompositor:
- return ApplyCreateCompositor(id,
- std::move(command.resource.compositor()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kDisplayCompositor:
- return ApplyCreateDisplayCompositor(
- id, std::move(command.resource.display_compositor()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kImagePipeCompositor:
- return ApplyCreateImagePipeCompositor(
- id, std::move(command.resource.image_pipe_compositor()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kLayerStack:
- return ApplyCreateLayerStack(id,
- std::move(command.resource.layer_stack()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kLayer:
- return ApplyCreateLayer(id, std::move(command.resource.layer()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::kVariable:
- return ApplyCreateVariable(id, std::move(command.resource.variable()));
- case ::fuchsia::ui::gfx::ResourceArgs::Tag::Invalid:
- // FIDL validation should make this impossible.
- FXL_CHECK(false);
- return false;
- }
-}
-
-bool Session::ApplyReleaseResourceCmd(
- ::fuchsia::ui::gfx::ReleaseResourceCmd command) {
- return resources_.RemoveResource(command.id);
-}
-
-bool Session::ApplyExportResourceCmd(
- ::fuchsia::ui::gfx::ExportResourceCmd command) {
- if (!command.token) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplyExportResourceCmd(): "
- "no token provided.";
- return false;
- }
- if (auto resource = resources_.FindResource<Resource>(command.id)) {
- return session_context_.resource_linker->ExportResource(
- resource.get(), std::move(command.token));
- }
- return false;
-}
-
-bool Session::ApplyImportResourceCmd(
- ::fuchsia::ui::gfx::ImportResourceCmd command) {
- if (!command.token) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplyImportResourceCmd(): "
- "no token provided.";
- return false;
- }
- ImportPtr import = fxl::MakeRefCounted<Import>(
- this, command.id, command.spec,
- session_context_.resource_linker->GetWeakPtr());
- return session_context_.resource_linker->ImportResource(
- import.get(), command.spec, std::move(command.token)) &&
- resources_.AddResource(command.id, std::move(import));
-}
-
-bool Session::ApplyAddChildCmd(::fuchsia::ui::gfx::AddChildCmd command) {
- // Find the parent and child nodes. We can add:
- // - Nodes to Nodes
- // - ViewHolders to Nodes
- // - Nodes to Views
- // TODO(SCN-795): Split these out into separate commands?
- if (auto parent = resources_.FindResource<Node>(
- command.node_id, ResourceMap::ErrorBehavior::kDontReportErrors)) {
- if (auto child = resources_.FindResource<Node>(
- command.child_id, ResourceMap::ErrorBehavior::kDontReportErrors)) {
- return parent->AddChild(std::move(child));
- } else if (auto child =
- resources_.FindResource<ViewHolder>(command.child_id)) {
- return parent->AddViewHolder(std::move(child));
- }
- } else if (auto parent = resources_.FindResource<View>(command.node_id)) {
- if (auto child = resources_.FindResource<Node>(command.child_id)) {
- return parent->AddChild(std::move(child));
- }
- }
- return false;
-}
-
-bool Session::ApplyAddPartCmd(::fuchsia::ui::gfx::AddPartCmd command) {
- // Find the parent and part nodes.
- if (auto parent_node = resources_.FindResource<Node>(command.node_id)) {
- if (auto part_node = resources_.FindResource<Node>(command.part_id)) {
- return parent_node->AddPart(std::move(part_node));
- }
- }
- return false;
-}
-
-bool Session::ApplyTakeSnapshotCmdHACK(
- ::fuchsia::ui::gfx::TakeSnapshotCmdHACK command) {
- async::PostTask(
- async_get_default_dispatcher(), [weak = weak_factory_.GetWeakPtr(),
- command = std::move(command)]() mutable {
- if (!weak) {
- if (auto callback = command.callback.Bind()) {
- // TODO(SCN-978): Return an error to the caller for invalid data.
- callback->OnData(fuchsia::mem::Buffer{});
- }
- return;
- }
-
- const auto& context = weak->session_context_;
- Resource* resource = nullptr;
- if (auto node = weak->resources_.FindResource<Node>(command.node_id)) {
- resource = node.get();
- } else if (command.node_id == 0) {
- // TODO(SCN-1170): get rid of SceneGraph::first_compositor().
- const auto& first_compositor_weak =
- context.scene_graph->first_compositor();
- if (first_compositor_weak) {
- resource = first_compositor_weak.get();
- }
- }
-
- if (resource == nullptr) {
- if (auto callback = command.callback.Bind()) {
- callback->OnData(fuchsia::mem::Buffer{});
- }
- return;
- }
-
- auto gpu_uploader =
- escher::BatchGpuUploader::New(context.escher->GetWeakPtr());
- Snapshotter snapshotter(gpu_uploader);
- // Take a snapshot and return the data in callback. The closure does
- // not need the snapshotter instance and is invoked after the instance
- // is destroyed.
- snapshotter.TakeSnapshot(resource, [callback = command.callback.Bind()](
- fuchsia::mem::Buffer snapshot) {
- callback->OnData(std::move(snapshot));
- });
- });
- return true;
-}
-
-bool Session::ApplyDetachCmd(::fuchsia::ui::gfx::DetachCmd command) {
- if (auto resource = resources_.FindResource<Resource>(command.id)) {
- return resource->Detach();
- }
- return false;
-}
-
-bool Session::ApplyDetachChildrenCmd(
- ::fuchsia::ui::gfx::DetachChildrenCmd command) {
- if (auto node = resources_.FindResource<Node>(command.node_id)) {
- return node->DetachChildren();
- }
- return false;
-}
-
-bool Session::ApplySetTagCmd(::fuchsia::ui::gfx::SetTagCmd command) {
- if (auto node = resources_.FindResource<Node>(command.node_id)) {
- return node->SetTagValue(command.tag_value);
- }
- return false;
-}
-
-bool Session::ApplySetTranslationCmd(
- ::fuchsia::ui::gfx::SetTranslationCmd command) {
- if (auto node = resources_.FindResource<Node>(command.id)) {
- if (IsVariable(command.value)) {
- if (auto variable = resources_.FindVariableResource<Vector3Variable>(
- command.value.variable_id)) {
- return node->SetTranslation(variable);
- }
- } else {
- return node->SetTranslation(UnwrapVector3(command.value));
- }
- }
- return false;
-}
-
-bool Session::ApplySetScaleCmd(::fuchsia::ui::gfx::SetScaleCmd command) {
- if (auto node = resources_.FindResource<Node>(command.id)) {
- if (IsVariable(command.value)) {
- if (auto variable = resources_.FindVariableResource<Vector3Variable>(
- command.value.variable_id)) {
- return node->SetScale(variable);
- }
- } else {
- return node->SetScale(UnwrapVector3(command.value));
- }
- }
- return false;
-}
-
-bool Session::ApplySetRotationCmd(::fuchsia::ui::gfx::SetRotationCmd command) {
- if (auto node = resources_.FindResource<Node>(command.id)) {
- if (IsVariable(command.value)) {
- if (auto variable = resources_.FindVariableResource<QuaternionVariable>(
- command.value.variable_id)) {
- return node->SetRotation(variable);
- }
- } else {
- return node->SetRotation(UnwrapQuaternion(command.value));
- }
- }
- return false;
-}
-
-bool Session::ApplySetAnchorCmd(::fuchsia::ui::gfx::SetAnchorCmd command) {
- if (auto node = resources_.FindResource<Node>(command.id)) {
- if (IsVariable(command.value)) {
- if (auto variable = resources_.FindVariableResource<Vector3Variable>(
- command.value.variable_id)) {
- return node->SetAnchor(variable);
- }
- }
- return node->SetAnchor(UnwrapVector3(command.value));
- }
- return false;
-}
-
-bool Session::ApplySetSizeCmd(::fuchsia::ui::gfx::SetSizeCmd command) {
- if (auto layer = resources_.FindResource<Layer>(command.id)) {
- if (IsVariable(command.value)) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplySetSizeCmd(): "
- "unimplemented for variable value.";
- return false;
- }
- return layer->SetSize(UnwrapVector2(command.value));
- }
- return false;
-}
-
-bool Session::ApplySetOpacityCmd(::fuchsia::ui::gfx::SetOpacityCmd command) {
- if (auto node = resources_.FindResource<OpacityNode>(command.node_id)) {
- node->SetOpacity(command.opacity);
- return true;
- }
- return false;
-}
-
-bool Session::ApplySendSizeChangeHintCmd(
- ::fuchsia::ui::gfx::SendSizeChangeHintCmdHACK command) {
- if (auto node = resources_.FindResource<Node>(command.node_id)) {
- return node->SendSizeChangeHint(command.width_change_factor,
- command.height_change_factor);
- }
- return false;
-}
-
-bool Session::ApplySetShapeCmd(::fuchsia::ui::gfx::SetShapeCmd command) {
- if (auto node = resources_.FindResource<ShapeNode>(command.node_id)) {
- if (auto shape = resources_.FindResource<Shape>(command.shape_id)) {
- node->SetShape(std::move(shape));
- return true;
- }
- }
- return false;
-}
-
-bool Session::ApplySetMaterialCmd(::fuchsia::ui::gfx::SetMaterialCmd command) {
- if (auto node = resources_.FindResource<ShapeNode>(command.node_id)) {
- if (auto material =
- resources_.FindResource<Material>(command.material_id)) {
- node->SetMaterial(std::move(material));
- return true;
- }
- }
- return false;
-}
-
-bool Session::ApplySetClipCmd(::fuchsia::ui::gfx::SetClipCmd command) {
- if (command.clip_id != 0) {
- // TODO(SCN-167): Support non-zero clip_id.
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplySetClipCmd(): only "
- "clip_to_self is implemented.";
- return false;
- }
-
- if (auto node = resources_.FindResource<Node>(command.node_id)) {
- return node->SetClipToSelf(command.clip_to_self);
- }
-
- return false;
-}
-
-bool Session::ApplySetHitTestBehaviorCmd(
- ::fuchsia::ui::gfx::SetHitTestBehaviorCmd command) {
- if (auto node = resources_.FindResource<Node>(command.node_id)) {
- return node->SetHitTestBehavior(command.hit_test_behavior);
- }
-
- return false;
-}
-
-bool Session::ApplySetViewPropertiesCmd(
- ::fuchsia::ui::gfx::SetViewPropertiesCmd command) {
- if (auto view_holder =
- resources_.FindResource<ViewHolder>(command.view_holder_id)) {
- view_holder->SetViewProperties(std::move(command.properties));
- return true;
- }
- return false;
-}
-
-bool Session::ApplySetCameraCmd(::fuchsia::ui::gfx::SetCameraCmd command) {
- if (auto renderer = resources_.FindResource<Renderer>(command.renderer_id)) {
- if (command.camera_id == 0) {
- renderer->SetCamera(nullptr);
- return true;
- } else if (auto camera =
- resources_.FindResource<Camera>(command.camera_id)) {
- renderer->SetCamera(std::move(camera));
- return true;
- }
- }
- return false;
-}
-
-bool Session::ApplySetTextureCmd(::fuchsia::ui::gfx::SetTextureCmd command) {
- if (auto material = resources_.FindResource<Material>(command.material_id)) {
- if (command.texture_id == 0) {
- material->SetTexture(nullptr);
- return true;
- } else if (auto image =
- resources_.FindResource<ImageBase>(command.texture_id)) {
- material->SetTexture(std::move(image));
- return true;
- }
- }
- return false;
-}
-
-bool Session::ApplySetColorCmd(::fuchsia::ui::gfx::SetColorCmd command) {
- if (auto material = resources_.FindResource<Material>(command.material_id)) {
- if (IsVariable(command.color)) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplySetColorCmd(): "
- "unimplemented for variable color.";
- return false;
- }
-
- auto& color = command.color.value;
- float red = static_cast<float>(color.red) / 255.f;
- float green = static_cast<float>(color.green) / 255.f;
- float blue = static_cast<float>(color.blue) / 255.f;
- float alpha = static_cast<float>(color.alpha) / 255.f;
- material->SetColor(red, green, blue, alpha);
- return true;
- }
- return false;
-}
-
-bool Session::ApplyBindMeshBuffersCmd(
- ::fuchsia::ui::gfx::BindMeshBuffersCmd command) {
- auto mesh = resources_.FindResource<MeshShape>(command.mesh_id);
- auto index_buffer = resources_.FindResource<Buffer>(command.index_buffer_id);
- auto vertex_buffer =
- resources_.FindResource<Buffer>(command.vertex_buffer_id);
- if (mesh && index_buffer && vertex_buffer) {
- return mesh->BindBuffers(std::move(index_buffer), command.index_format,
- command.index_offset, command.index_count,
- std::move(vertex_buffer), command.vertex_format,
- command.vertex_offset, command.vertex_count,
- Unwrap(command.bounding_box));
- }
- return false;
-}
-
-bool Session::ApplyAddLayerCmd(::fuchsia::ui::gfx::AddLayerCmd command) {
- auto layer_stack =
- resources_.FindResource<LayerStack>(command.layer_stack_id);
- auto layer = resources_.FindResource<Layer>(command.layer_id);
- if (layer_stack && layer) {
- return layer_stack->AddLayer(std::move(layer));
- }
- return false;
-}
-
-bool Session::ApplyRemoveLayerCmd(::fuchsia::ui::gfx::RemoveLayerCmd command) {
- auto layer_stack =
- resources_.FindResource<LayerStack>(command.layer_stack_id);
- auto layer = resources_.FindResource<Layer>(command.layer_id);
- if (layer_stack && layer) {
- return layer_stack->RemoveLayer(std::move(layer));
- }
- return false;
-}
-
-bool Session::ApplyRemoveAllLayersCmd(
- ::fuchsia::ui::gfx::RemoveAllLayersCmd command) {
- auto layer_stack =
- resources_.FindResource<LayerStack>(command.layer_stack_id);
- if (layer_stack) {
- return layer_stack->RemoveAllLayers();
- }
- return false;
-}
-
-bool Session::ApplySetLayerStackCmd(
- ::fuchsia::ui::gfx::SetLayerStackCmd command) {
- auto compositor = resources_.FindResource<Compositor>(command.compositor_id);
- auto layer_stack =
- resources_.FindResource<LayerStack>(command.layer_stack_id);
- if (compositor && layer_stack) {
- return compositor->SetLayerStack(std::move(layer_stack));
- }
- return false;
-}
-
-bool Session::ApplySetRendererCmd(::fuchsia::ui::gfx::SetRendererCmd command) {
- auto layer = resources_.FindResource<Layer>(command.layer_id);
- auto renderer = resources_.FindResource<Renderer>(command.renderer_id);
-
- if (layer && renderer) {
- return layer->SetRenderer(std::move(renderer));
- }
- return false;
-}
-
-bool Session::ApplySetRendererParamCmd(
- ::fuchsia::ui::gfx::SetRendererParamCmd command) {
- auto renderer = resources_.FindResource<Renderer>(command.renderer_id);
- if (renderer) {
- switch (command.param.Which()) {
- case ::fuchsia::ui::gfx::RendererParam::Tag::kShadowTechnique:
- return renderer->SetShadowTechnique(command.param.shadow_technique());
- case ::fuchsia::ui::gfx::RendererParam::Tag::kRenderFrequency:
- // TODO(SCN-1169): SetRenderContinuously should only affect the
- // compositor that has the renderer attached to it.
- session_context_.frame_scheduler->SetRenderContinuously(
- command.param.render_frequency() ==
- ::fuchsia::ui::gfx::RenderFrequency::CONTINUOUSLY);
- return true;
- case ::fuchsia::ui::gfx::RendererParam::Tag::Invalid:
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplySetRendererParamCmd(): "
- "invalid param.";
- }
- }
- return false;
-}
-
-bool Session::ApplySetEventMaskCmd(
- ::fuchsia::ui::gfx::SetEventMaskCmd command) {
- if (auto r = resources_.FindResource<Resource>(command.id)) {
- return r->SetEventMask(command.event_mask);
- }
- return false;
-}
-
-bool Session::ApplySetCameraTransformCmd(
- ::fuchsia::ui::gfx::SetCameraTransformCmd command) {
- // TODO(SCN-123): support variables.
- if (IsVariable(command.eye_position) || IsVariable(command.eye_look_at) ||
- IsVariable(command.eye_up)) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplySetCameraTransformCmd(): "
- "unimplemented: variable properties.";
- return false;
- } else if (auto camera = resources_.FindResource<Camera>(command.camera_id)) {
- camera->SetTransform(UnwrapVector3(command.eye_position),
- UnwrapVector3(command.eye_look_at),
- UnwrapVector3(command.eye_up));
- return true;
- }
- return false;
-}
-
-bool Session::ApplySetCameraProjectionCmd(
- ::fuchsia::ui::gfx::SetCameraProjectionCmd command) {
- // TODO(SCN-123): support variables.
- if (IsVariable(command.fovy)) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplySetCameraProjectionCmd(): "
- "unimplemented: variable properties.";
- return false;
- } else if (auto camera = resources_.FindResource<Camera>(command.camera_id)) {
- camera->SetProjection(UnwrapFloat(command.fovy));
- return true;
- }
- return false;
-}
-
-bool Session::ApplySetStereoCameraProjectionCmd(
- ::fuchsia::ui::gfx::SetStereoCameraProjectionCmd command) {
- if (IsVariable(command.left_projection) ||
- IsVariable(command.right_projection)) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplySetStereoCameraProjectionOp(): "
- "unimplemented: variable properties.";
- return false;
- } else if (auto stereo_camera =
- resources_.FindResource<StereoCamera>(command.camera_id)) {
- stereo_camera->SetStereoProjection(Unwrap(command.left_projection.value),
- Unwrap(command.right_projection.value));
- return true;
- }
- return false;
-}
-
-bool Session::ApplySetCameraPoseBufferCmd(
- ::fuchsia::ui::gfx::SetCameraPoseBufferCmd command) {
- if (command.base_time > dispatcher_clock_now()) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplySetCameraPoseBufferCmd(): "
- "base time not in the past";
- return false;
- }
-
- auto buffer = resources_.FindResource<Buffer>(command.buffer_id);
- if (!buffer) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplySetCameraPoseBufferCmd(): "
- "invalid buffer ID";
- return false;
- }
-
- if (command.num_entries < 1) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplySetCameraPoseBufferCmd(): "
- "must have at least one entry in the pose buffer";
- return false;
- }
-
- if (buffer->size() < command.num_entries * sizeof(escher::hmd::Pose)) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplySetCameraPoseBufferCmd(): "
- "buffer is not large enough";
- return false;
- }
-
- auto camera = resources_.FindResource<Camera>(command.camera_id);
- if (!camera) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplySetCameraPoseBufferCmd(): "
- "invalid camera ID";
- return false;
- }
-
- camera->SetPoseBuffer(buffer, command.num_entries, command.base_time,
- command.time_interval);
-
- return true;
-}
-
-bool Session::ApplySetLightColorCmd(
- ::fuchsia::ui::gfx::SetLightColorCmd command) {
- // TODO(SCN-123): support variables.
- if (command.color.variable_id) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplySetLightColorCmd(): "
- "unimplemented: variable color.";
- return false;
- } else if (auto light = resources_.FindResource<Light>(command.light_id)) {
- return light->SetColor(Unwrap(command.color.value));
- }
- return false;
-}
-
-bool Session::ApplySetLightDirectionCmd(
- ::fuchsia::ui::gfx::SetLightDirectionCmd command) {
- // TODO(SCN-123): support variables.
- if (command.direction.variable_id) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplySetLightDirectionCmd(): "
- "unimplemented: variable direction.";
- return false;
- } else if (auto light =
- resources_.FindResource<DirectionalLight>(command.light_id)) {
- return light->SetDirection(Unwrap(command.direction.value));
- }
- return false;
-}
-
-bool Session::ApplyAddLightCmd(::fuchsia::ui::gfx::AddLightCmd command) {
- if (auto scene = resources_.FindResource<Scene>(command.scene_id)) {
- if (auto light = resources_.FindResource<Light>(command.light_id)) {
- return scene->AddLight(std::move(light));
- }
- }
-
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplyAddLightCmd(): unimplemented.";
- return false;
-}
-
-bool Session::ApplyDetachLightCmd(::fuchsia::ui::gfx::DetachLightCmd command) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplyDetachLightCmd(): unimplemented.";
- return false;
-}
-
-bool Session::ApplyDetachLightsCmd(
- ::fuchsia::ui::gfx::DetachLightsCmd command) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplyDetachLightsCmd(): unimplemented.";
- return false;
-}
-
-bool Session::ApplySetLabelCmd(::fuchsia::ui::gfx::SetLabelCmd command) {
- if (auto r = resources_.FindResource<Resource>(command.id)) {
- return r->SetLabel(command.label);
- }
- return false;
-}
-
-bool Session::ApplySetDisableClippingCmd(
- ::fuchsia::ui::gfx::SetDisableClippingCmd command) {
- if (auto r = resources_.FindResource<Renderer>(command.renderer_id)) {
- r->DisableClipping(command.disable_clipping);
- return true;
- }
- return false;
-}
-
-bool Session::ApplyCreateMemory(ResourceId id,
- ::fuchsia::ui::gfx::MemoryArgs args) {
- auto memory = CreateMemory(id, std::move(args));
- return memory ? resources_.AddResource(id, std::move(memory)) : false;
-}
-
-bool Session::ApplyCreateImage(ResourceId id,
- ::fuchsia::ui::gfx::ImageArgs args) {
- if (auto memory = resources_.FindResource<Memory>(args.memory_id)) {
- if (auto image = CreateImage(id, std::move(memory), args)) {
- return resources_.AddResource(id, std::move(image));
- }
- }
-
- return false;
-}
-
-bool Session::ApplyCreateImagePipe(ResourceId id,
- ::fuchsia::ui::gfx::ImagePipeArgs args) {
- auto image_pipe = fxl::MakeRefCounted<ImagePipe>(
- this, id, std::move(args.image_pipe_request),
- session_context_.update_scheduler);
- return resources_.AddResource(id, image_pipe);
-}
-
-bool Session::ApplyCreateBuffer(ResourceId id,
- ::fuchsia::ui::gfx::BufferArgs args) {
- if (auto memory = resources_.FindResource<Memory>(args.memory_id)) {
- if (auto buffer = CreateBuffer(id, std::move(memory), args.memory_offset,
- args.num_bytes)) {
- return resources_.AddResource(id, std::move(buffer));
- }
- }
- return false;
-}
-
-bool Session::ApplyCreateScene(ResourceId id,
- ::fuchsia::ui::gfx::SceneArgs args) {
- auto scene = CreateScene(id, std::move(args));
- return scene ? resources_.AddResource(id, std::move(scene)) : false;
-}
-
-bool Session::ApplyCreateCamera(ResourceId id,
- ::fuchsia::ui::gfx::CameraArgs args) {
- auto camera = CreateCamera(id, std::move(args));
- return camera ? resources_.AddResource(id, std::move(camera)) : false;
-}
-
-bool Session::ApplyCreateStereoCamera(
- ResourceId id, ::fuchsia::ui::gfx::StereoCameraArgs args) {
- auto camera = CreateStereoCamera(id, args);
- return camera ? resources_.AddResource(id, std::move(camera)) : false;
-}
-
-bool Session::ApplyCreateRenderer(ResourceId id,
- ::fuchsia::ui::gfx::RendererArgs args) {
- auto renderer = CreateRenderer(id, std::move(args));
- return renderer ? resources_.AddResource(id, std::move(renderer)) : false;
-}
-
-bool Session::ApplyCreateAmbientLight(
- ResourceId id, ::fuchsia::ui::gfx::AmbientLightArgs args) {
- auto light = CreateAmbientLight(id);
- return light ? resources_.AddResource(id, std::move(light)) : false;
-}
-
-bool Session::ApplyCreateDirectionalLight(
- ResourceId id, ::fuchsia::ui::gfx::DirectionalLightArgs args) {
- auto light = CreateDirectionalLight(id);
- return light ? resources_.AddResource(id, std::move(light)) : false;
-}
-
-bool Session::ApplyCreateRectangle(ResourceId id,
- ::fuchsia::ui::gfx::RectangleArgs args) {
- if (!AssertValueIsOfType(args.width, kFloatValueTypes) ||
- !AssertValueIsOfType(args.height, kFloatValueTypes)) {
- return false;
- }
-
- // TODO(SCN-123): support variables.
- if (IsVariable(args.width) || IsVariable(args.height)) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplyCreateRectangle(): "
- "unimplemented: variable width/height.";
- return false;
- }
-
- auto rectangle =
- CreateRectangle(id, args.width.vector1(), args.height.vector1());
- return rectangle ? resources_.AddResource(id, std::move(rectangle)) : false;
-}
-
-bool Session::ApplyCreateRoundedRectangle(
- CommandContext* command_context, ResourceId id,
- ::fuchsia::ui::gfx::RoundedRectangleArgs args) {
- if (!AssertValueIsOfType(args.width, kFloatValueTypes) ||
- !AssertValueIsOfType(args.height, kFloatValueTypes) ||
- !AssertValueIsOfType(args.top_left_radius, kFloatValueTypes) ||
- !AssertValueIsOfType(args.top_right_radius, kFloatValueTypes) ||
- !AssertValueIsOfType(args.bottom_left_radius, kFloatValueTypes) ||
- !AssertValueIsOfType(args.bottom_right_radius, kFloatValueTypes)) {
- return false;
- }
-
- // TODO(SCN-123): support variables.
- if (IsVariable(args.width) || IsVariable(args.height) ||
- IsVariable(args.top_left_radius) || IsVariable(args.top_right_radius) ||
- IsVariable(args.bottom_left_radius) ||
- IsVariable(args.bottom_right_radius)) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplyCreateRoundedRectangle(): "
- "unimplemented: variable width/height/radii.";
- return false;
- }
-
- const float width = args.width.vector1();
- const float height = args.height.vector1();
- const float top_left_radius = args.top_left_radius.vector1();
- const float top_right_radius = args.top_right_radius.vector1();
- const float bottom_right_radius = args.bottom_right_radius.vector1();
- const float bottom_left_radius = args.bottom_left_radius.vector1();
-
- auto rectangle = CreateRoundedRectangle(
- command_context, id, width, height, top_left_radius, top_right_radius,
- bottom_right_radius, bottom_left_radius);
- return rectangle ? resources_.AddResource(id, std::move(rectangle)) : false;
-}
-
-bool Session::ApplyCreateCircle(ResourceId id,
- ::fuchsia::ui::gfx::CircleArgs args) {
- if (!AssertValueIsOfType(args.radius, kFloatValueTypes)) {
- return false;
- }
-
- // TODO(SCN-123): support variables.
- if (IsVariable(args.radius)) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplyCreateCircle(): "
- "unimplemented: variable radius.";
- return false;
- }
-
- auto circle = CreateCircle(id, args.radius.vector1());
- return circle ? resources_.AddResource(id, std::move(circle)) : false;
-}
-
-bool Session::ApplyCreateMesh(ResourceId id,
- ::fuchsia::ui::gfx::MeshArgs args) {
- auto mesh = CreateMesh(id);
- return mesh ? resources_.AddResource(id, std::move(mesh)) : false;
-}
-
-bool Session::ApplyCreateMaterial(ResourceId id,
- ::fuchsia::ui::gfx::MaterialArgs args) {
- auto material = CreateMaterial(id);
- return material ? resources_.AddResource(id, std::move(material)) : false;
-}
-
-bool Session::ApplyCreateView(ResourceId id,
- ::fuchsia::ui::gfx::ViewArgs args) {
- // Sanity check. We also rely on FIDL to enforce this for us, although it
- // does not at the moment.
- FXL_DCHECK(args.token)
- << "scenic_impl::gfx::Session::ApplyCreateView(): no token provided.";
-
- if (auto view = CreateView(id, std::move(args))) {
- view->As<View>()->Connect(); // Initiate the link.
- resources_.AddResource(id, std::move(view));
- return true;
- }
- return false;
-}
-
-bool Session::ApplyCreateViewHolder(ResourceId id,
- ::fuchsia::ui::gfx::ViewHolderArgs args) {
- // Sanity check. We also rely on FIDL to enforce this for us, although it
- // does not at the moment
- FXL_DCHECK(args.token) << "scenic_impl::gfx::Session::ApplyCreateViewHolder()"
- ": no token provided.";
-
- if (auto view_holder = CreateViewHolder(id, std::move(args))) {
- view_holder->As<ViewHolder>()->Connect(); // Initiate the link.
- resources_.AddResource(id, std::move(view_holder));
- return true;
- }
- return false;
-}
-
-bool Session::ApplyCreateClipNode(ResourceId id,
- ::fuchsia::ui::gfx::ClipNodeArgs args) {
- auto node = CreateClipNode(id, std::move(args));
- return node ? resources_.AddResource(id, std::move(node)) : false;
-}
-
-bool Session::ApplyCreateEntityNode(ResourceId id,
- ::fuchsia::ui::gfx::EntityNodeArgs args) {
- auto node = CreateEntityNode(id, std::move(args));
- return node ? resources_.AddResource(id, std::move(node)) : false;
-}
-
-bool Session::ApplyCreateOpacityNode(ResourceId id,
- ::fuchsia::ui::gfx::OpacityNodeArgs args) {
- auto node = CreateOpacityNode(id, args);
- return node ? resources_.AddResource(id, std::move(node)) : false;
-}
-
-bool Session::ApplyCreateShapeNode(ResourceId id,
- ::fuchsia::ui::gfx::ShapeNodeArgs args) {
- auto node = CreateShapeNode(id, std::move(args));
- return node ? resources_.AddResource(id, std::move(node)) : false;
-}
-
-bool Session::ApplyCreateCompositor(ResourceId id,
- ::fuchsia::ui::gfx::CompositorArgs args) {
- auto compositor = CreateCompositor(id, std::move(args));
- return compositor ? resources_.AddResource(id, std::move(compositor)) : false;
-}
-
-bool Session::ApplyCreateDisplayCompositor(
- ResourceId id, ::fuchsia::ui::gfx::DisplayCompositorArgs args) {
- auto compositor = CreateDisplayCompositor(id, std::move(args));
- return compositor ? resources_.AddResource(id, std::move(compositor)) : false;
-}
-
-bool Session::ApplyCreateImagePipeCompositor(
- ResourceId id, ::fuchsia::ui::gfx::ImagePipeCompositorArgs args) {
- auto compositor = CreateImagePipeCompositor(id, std::move(args));
- return compositor ? resources_.AddResource(id, std::move(compositor)) : false;
-}
-
-bool Session::ApplyCreateLayerStack(ResourceId id,
- ::fuchsia::ui::gfx::LayerStackArgs args) {
- auto layer_stack = CreateLayerStack(id, std::move(args));
- return layer_stack ? resources_.AddResource(id, std::move(layer_stack))
- : false;
-}
-
-bool Session::ApplyCreateLayer(ResourceId id,
- ::fuchsia::ui::gfx::LayerArgs args) {
- auto layer = CreateLayer(id, std::move(args));
- return layer ? resources_.AddResource(id, std::move(layer)) : false;
-}
-
-bool Session::ApplyCreateVariable(ResourceId id,
- ::fuchsia::ui::gfx::VariableArgs args) {
- auto variable = CreateVariable(id, std::move(args));
- return variable ? resources_.AddResource(id, std::move(variable)) : false;
-}
-
-ResourcePtr Session::CreateMemory(ResourceId id,
- ::fuchsia::ui::gfx::MemoryArgs args) {
- return Memory::New(this, id, std::move(args), error_reporter_);
-}
-
-ResourcePtr Session::CreateImage(ResourceId id, MemoryPtr memory,
- ::fuchsia::ui::gfx::ImageArgs args) {
- return Image::New(this, id, memory, args.info, args.memory_offset,
- error_reporter_);
-}
-
-ResourcePtr Session::CreateBuffer(ResourceId id, MemoryPtr memory,
- uint32_t memory_offset, uint32_t num_bytes) {
- if (memory_offset + num_bytes > memory->size()) {
- error_reporter_->ERROR() << "scenic_impl::gfx::Session::CreateBuffer(): "
- "buffer does not fit within memory (buffer "
- "offset: "
- << memory_offset << ", buffer size: " << num_bytes
- << ", memory size: " << memory->size() << ")";
- return ResourcePtr();
- }
-
- // Make a pointer to a subregion of the memory, if necessary.
- escher::GpuMemPtr gpu_mem =
- (memory_offset > 0 || num_bytes < memory->size())
- ? memory->GetGpuMem()->Suballocate(num_bytes, memory_offset)
- : memory->GetGpuMem();
-
- return fxl::MakeRefCounted<Buffer>(this, id, std::move(gpu_mem),
- std::move(memory));
-}
-
-ResourcePtr Session::CreateScene(ResourceId id,
- ::fuchsia::ui::gfx::SceneArgs args) {
- return fxl::MakeRefCounted<Scene>(this, id);
-}
-
-ResourcePtr Session::CreateCamera(ResourceId id,
- ::fuchsia::ui::gfx::CameraArgs args) {
- if (auto scene = resources_.FindResource<Scene>(args.scene_id)) {
- return fxl::MakeRefCounted<Camera>(this, id, std::move(scene));
- }
- return ResourcePtr();
-}
-
-ResourcePtr Session::CreateStereoCamera(
- ResourceId id, const ::fuchsia::ui::gfx::StereoCameraArgs args) {
- if (auto scene = resources_.FindResource<Scene>(args.scene_id)) {
- return fxl::MakeRefCounted<StereoCamera>(this, id, std::move(scene));
- }
- return ResourcePtr();
-}
-
-ResourcePtr Session::CreateRenderer(ResourceId id,
- ::fuchsia::ui::gfx::RendererArgs args) {
- return fxl::MakeRefCounted<Renderer>(this, id);
-}
-
-ResourcePtr Session::CreateAmbientLight(ResourceId id) {
- return fxl::MakeRefCounted<AmbientLight>(this, id);
-}
-
-ResourcePtr Session::CreateDirectionalLight(ResourceId id) {
- return fxl::MakeRefCounted<DirectionalLight>(this, id);
-}
-
-ResourcePtr Session::CreateView(ResourceId id,
- ::fuchsia::ui::gfx::ViewArgs args) {
- ViewLinker* view_linker = session_context_.view_linker;
- ViewLinker::ImportLink link =
- view_linker->CreateImport(std::move(args.token), error_reporter());
-
- // Create a View if the Link was successfully registered.
- if (link.valid()) {
- return fxl::MakeRefCounted<View>(this, id, std::move(link));
- }
- return nullptr;
-}
-
-ResourcePtr Session::CreateViewHolder(ResourceId id,
- ::fuchsia::ui::gfx::ViewHolderArgs args) {
- ViewLinker* view_linker = session_context_.view_linker;
- ViewLinker::ExportLink link =
- view_linker->CreateExport(std::move(args.token), error_reporter());
-
- // Create a ViewHolder if the Link was successfully registered.
- if (link.valid()) {
- return fxl::MakeRefCounted<ViewHolder>(this, id, std::move(link));
- }
- return nullptr;
-}
-
-ResourcePtr Session::CreateClipNode(ResourceId id,
- ::fuchsia::ui::gfx::ClipNodeArgs args) {
- error_reporter_->ERROR() << "scenic_impl::gfx::Session::CreateClipNode(): "
- "unimplemented.";
- return ResourcePtr();
-}
-
-ResourcePtr Session::CreateEntityNode(ResourceId id,
- ::fuchsia::ui::gfx::EntityNodeArgs args) {
- return fxl::MakeRefCounted<EntityNode>(this, id);
-}
-
-ResourcePtr Session::CreateOpacityNode(
- ResourceId id, ::fuchsia::ui::gfx::OpacityNodeArgs args) {
- return fxl::MakeRefCounted<OpacityNode>(this, id);
-}
-
-ResourcePtr Session::CreateShapeNode(ResourceId id,
- ::fuchsia::ui::gfx::ShapeNodeArgs args) {
- return fxl::MakeRefCounted<ShapeNode>(this, id);
-}
-
-ResourcePtr Session::CreateCompositor(ResourceId id,
- ::fuchsia::ui::gfx::CompositorArgs args) {
- return Compositor::New(this, id, session_context_.scene_graph);
-}
-
-ResourcePtr Session::CreateDisplayCompositor(
- ResourceId id, ::fuchsia::ui::gfx::DisplayCompositorArgs args) {
- Display* display = session_context_.display_manager->default_display();
- if (!display) {
- error_reporter_->ERROR() << "There is no default display available.";
- return nullptr;
- }
-
- if (display->is_claimed()) {
- error_reporter_->ERROR() << "The default display has already been claimed "
- "by another compositor.";
- return nullptr;
- }
-
- return fxl::AdoptRef(new DisplayCompositor(
- this, id, session_context_.scene_graph, display,
- SwapchainFactory::CreateDisplaySwapchain(
- display, session_context_.display_manager,
- session_context_.event_timestamper, session_context_.escher)));
-}
-
-ResourcePtr Session::CreateImagePipeCompositor(
- ResourceId id, ::fuchsia::ui::gfx::ImagePipeCompositorArgs args) {
- // TODO(SCN-179)
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::ApplyCreateImagePipeCompositor() "
- "is unimplemented (SCN-179)";
- return ResourcePtr();
-}
-
-ResourcePtr Session::CreateLayerStack(ResourceId id,
- ::fuchsia::ui::gfx::LayerStackArgs args) {
- return fxl::MakeRefCounted<LayerStack>(this, id);
-}
-
-ResourcePtr Session::CreateVariable(ResourceId id,
- ::fuchsia::ui::gfx::VariableArgs args) {
- fxl::RefPtr<Variable> variable;
- switch (args.type) {
- case ::fuchsia::ui::gfx::ValueType::kVector1:
- variable = fxl::MakeRefCounted<FloatVariable>(this, id);
- break;
- case ::fuchsia::ui::gfx::ValueType::kVector2:
- variable = fxl::MakeRefCounted<Vector2Variable>(this, id);
- break;
- case ::fuchsia::ui::gfx::ValueType::kVector3:
- variable = fxl::MakeRefCounted<Vector3Variable>(this, id);
- break;
- case ::fuchsia::ui::gfx::ValueType::kVector4:
- variable = fxl::MakeRefCounted<Vector4Variable>(this, id);
- break;
- case ::fuchsia::ui::gfx::ValueType::kMatrix4:
- variable = fxl::MakeRefCounted<Matrix4x4Variable>(this, id);
- break;
- case ::fuchsia::ui::gfx::ValueType::kColorRgb:
- // not yet supported
- variable = nullptr;
- break;
- case ::fuchsia::ui::gfx::ValueType::kColorRgba:
- // not yet supported
- variable = nullptr;
- break;
- case ::fuchsia::ui::gfx::ValueType::kQuaternion:
- variable = fxl::MakeRefCounted<QuaternionVariable>(this, id);
- break;
- case ::fuchsia::ui::gfx::ValueType::kFactoredTransform:
- /* variable = fxl::MakeRefCounted<TransformVariable>(this, id); */
- variable = nullptr;
- break;
- case ::fuchsia::ui::gfx::ValueType::kNone:
- break;
- }
- if (variable && variable->SetValue(args.initial_value)) {
- return variable;
- }
- return nullptr;
-}
-
-ResourcePtr Session::CreateLayer(ResourceId id,
- ::fuchsia::ui::gfx::LayerArgs args) {
- return fxl::MakeRefCounted<Layer>(this, id);
-}
-
-ResourcePtr Session::CreateCircle(ResourceId id, float initial_radius) {
- return fxl::MakeRefCounted<CircleShape>(this, id, initial_radius);
-}
-
-ResourcePtr Session::CreateRectangle(ResourceId id, float width, float height) {
- return fxl::MakeRefCounted<RectangleShape>(this, id, width, height);
-}
-
-ResourcePtr Session::CreateRoundedRectangle(CommandContext* command_context,
- ResourceId id, float width,
- float height, float top_left_radius,
- float top_right_radius,
- float bottom_right_radius,
- float bottom_left_radius) {
- auto factory = session_context_.escher_rounded_rect_factory;
- if (!factory) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session::CreateRoundedRectangle(): "
- "no RoundedRectFactory available.";
- return ResourcePtr();
- }
-
- // If radii sum exceeds width or height, scale them down.
- float top_radii_sum = top_left_radius + top_right_radius;
- float top_scale = std::min(width / top_radii_sum, 1.f);
-
- float bottom_radii_sum = bottom_left_radius + bottom_right_radius;
- float bottom_scale = std::min(width / bottom_radii_sum, 1.f);
-
- float left_radii_sum = top_left_radius + bottom_left_radius;
- float left_scale = std::min(height / left_radii_sum, 1.f);
-
- float right_radii_sum = top_right_radius + bottom_right_radius;
- float right_scale = std::min(height / right_radii_sum, 1.f);
-
- top_left_radius *= std::min(top_scale, left_scale);
- top_right_radius *= std::min(top_scale, right_scale);
- bottom_left_radius *= std::min(bottom_scale, left_scale);
- bottom_right_radius *= std::min(bottom_scale, right_scale);
-
- escher::RoundedRectSpec rect_spec(width, height, top_left_radius,
- top_right_radius, bottom_right_radius,
- bottom_left_radius);
- escher::MeshSpec mesh_spec{escher::MeshAttribute::kPosition2D |
- escher::MeshAttribute::kUV};
-
- return fxl::MakeRefCounted<RoundedRectangleShape>(
- this, id, rect_spec,
- factory->NewRoundedRect(rect_spec, mesh_spec,
- command_context->batch_gpu_uploader()));
-}
-
-ResourcePtr Session::CreateMesh(ResourceId id) {
- return fxl::MakeRefCounted<MeshShape>(this, id);
-}
-
-ResourcePtr Session::CreateMaterial(ResourceId id) {
- return fxl::MakeRefCounted<Material>(this, id);
-}
-
-void Session::TearDown() {
- if (!is_valid_) {
- // TearDown already called.
- return;
- }
- is_valid_ = false;
+Session::~Session() {
resources_.Clear();
scheduled_image_pipe_updates_ = {};
- // We assume the channel for the associated ::fuchsia::ui::gfx::Session is
- // closed because SessionHandler closes it before calling this method. The
- // channel *must* be closed before we clear |scheduled_updates_|, since it
- // contains pending callbacks to ::fuchsia::ui::gfx::Session::Present(); if it
- // were not closed, we would have to invoke those callbacks before destroying
- // them.
+ // We assume the channel for the associated gfx::Session is closed by
+ // SessionHandler before this point, since |scheduled_updates_| contains
+ // pending callbacks to gfx::Session::Present(). If the channel was not closed
+ // we would have to invoke those callbacks before destroying them.
scheduled_updates_ = {};
fences_to_release_on_next_update_.clear();
@@ -1429,12 +85,14 @@
auto exported_count =
session_context_.resource_linker->NumExportsForSession(this);
FXL_CHECK(resource_count_ == 0)
- << "Session::TearDown(): Not all resources have been collected. "
+ << "Session::~Session(): Not all resources have been collected. "
"Exported resources: "
<< exported_count
<< ", total outstanding resources: " << resource_count_;
}
error_reporter_ = nullptr;
+
+ weak_factory_.InvalidateWeakPtrs();
}
ErrorReporter* Session::error_reporter() const {
@@ -1443,134 +101,106 @@
EventReporter* Session::event_reporter() const { return event_reporter_; }
-bool Session::AssertValueIsOfType(const ::fuchsia::ui::gfx::Value& value,
- const ::fuchsia::ui::gfx::Value::Tag* tags,
- size_t tag_count) {
- using ::operator<<; // From print_commands.h
- FXL_DCHECK(tag_count > 0);
- for (size_t i = 0; i < tag_count; ++i) {
- if (value.Which() == tags[i]) {
- return true;
- }
- }
- std::ostringstream str;
- if (tag_count == 1) {
- str << ", which is not the expected type: " << tags[0] << ".";
- } else {
- str << ", which is not one of the expected types (" << tags[0];
- for (size_t i = 1; i < tag_count; ++i) {
- str << ", " << tags[i];
- }
- str << ").";
- }
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session: received value of type: " << value.Which()
- << str.str();
- return false;
-}
-
bool Session::ScheduleUpdate(
uint64_t requested_presentation_time,
std::vector<::fuchsia::ui::gfx::Command> commands,
::std::vector<zx::event> acquire_fences,
::std::vector<zx::event> release_events,
fuchsia::ui::scenic::Session::PresentCallback callback) {
- if (is_valid()) {
- uint64_t last_scheduled_presentation_time =
- last_applied_update_presentation_time_;
- if (!scheduled_updates_.empty()) {
- last_scheduled_presentation_time =
- std::max(last_scheduled_presentation_time,
- scheduled_updates_.back().presentation_time);
- }
-
- if (requested_presentation_time < last_scheduled_presentation_time) {
- error_reporter_->ERROR()
- << "scenic_impl::gfx::Session: Present called with out-of-order "
- "presentation time. "
- << "requested presentation time=" << requested_presentation_time
- << ", last scheduled presentation time="
- << last_scheduled_presentation_time << ".";
- return false;
- }
-
- // If we're not running headless, warn if the requested presesentation time
- // is not reasonable.
- if (session_context_.frame_scheduler &&
- session_context_.display_manager->default_display()) {
- std::pair<zx_time_t, zx_time_t> target_times =
- session_context_.frame_scheduler
- ->ComputeTargetPresentationAndWakeupTimes(
- requested_presentation_time);
- uint64_t target_presentation_time = target_times.first;
-
- zx_time_t vsync_interval =
- session_context_.display_manager->default_display()
- ->GetVsyncInterval();
- // TODO(SCN-723): Re-enable warning when requested_presentation_time == 0
- // after Flutter engine is fixed.
- if (requested_presentation_time != 0 &&
- target_presentation_time - vsync_interval >
- requested_presentation_time) {
- // Present called with too early of a presentation time.
- TRACE_INSTANT("gfx", "Session requested too early presentation time",
- TRACE_SCOPE_PROCESS, "session_id", id(),
- "requested presentation time",
- requested_presentation_time, "target presentation time",
- target_presentation_time);
- }
- }
- auto acquire_fence_set =
- std::make_unique<escher::FenceSetListener>(std::move(acquire_fences));
- // TODO: Consider calling ScheduleUpdateForSession immediately if
- // acquire_fence_set is already ready (which is the case if there are
- // zero acquire fences).
-
- acquire_fence_set->WaitReadyAsync(
- [weak = weak_factory_.GetWeakPtr(), requested_presentation_time] {
- if (weak)
- weak->session_context_.session_manager->ScheduleUpdateForSession(
- weak->session_context_.update_scheduler,
- requested_presentation_time, SessionPtr(weak.get()));
- });
-
- scheduled_updates_.push(
- Update{requested_presentation_time, std::move(commands),
- std::move(acquire_fence_set), std::move(release_events),
- std::move(callback)});
+ uint64_t last_scheduled_presentation_time =
+ last_applied_update_presentation_time_;
+ if (!scheduled_updates_.empty()) {
+ last_scheduled_presentation_time =
+ std::max(last_scheduled_presentation_time,
+ scheduled_updates_.back().presentation_time);
}
+
+ if (requested_presentation_time < last_scheduled_presentation_time) {
+ error_reporter_->ERROR()
+ << "scenic_impl::gfx::Session: Present called with out-of-order "
+ "presentation time. "
+ << "requested presentation time=" << requested_presentation_time
+ << ", last scheduled presentation time="
+ << last_scheduled_presentation_time << ".";
+ return false;
+ }
+
+ // If we're not running headless, warn if the requested presesentation time
+ // is not reasonable.
+ if (session_context_.frame_scheduler &&
+ session_context_.display_manager->default_display()) {
+ std::pair<zx_time_t, zx_time_t> target_times =
+ session_context_.frame_scheduler
+ ->ComputeTargetPresentationAndWakeupTimes(
+ requested_presentation_time);
+ uint64_t target_presentation_time = target_times.first;
+ zx_time_t vsync_interval =
+ session_context_.display_manager->default_display()->GetVsyncInterval();
+ // TODO(SCN-723): Re-enable warning when requested_presentation_time == 0
+ // after Flutter engine is fixed.
+ if (requested_presentation_time != 0 &&
+ target_presentation_time - vsync_interval >
+ requested_presentation_time) {
+ // Present called with too early of a presentation time.
+ TRACE_INSTANT("gfx", "Session requested too early presentation time",
+ TRACE_SCOPE_PROCESS, "session_id", id(),
+ "requested presentation time", requested_presentation_time,
+ "target presentation time", target_presentation_time);
+ }
+ }
+
+ auto acquire_fence_set =
+ std::make_unique<escher::FenceSetListener>(std::move(acquire_fences));
+ // TODO: Consider calling ScheduleUpdateForSession immediately if
+ // acquire_fence_set is already ready (which is the case if there are
+ // zero acquire fences).
+
+ acquire_fence_set->WaitReadyAsync(
+ [weak = GetWeakPtr(), requested_presentation_time] {
+ if (weak) {
+ weak->session_context_.session_manager->ScheduleUpdateForSession(
+ weak->session_context_.update_scheduler,
+ requested_presentation_time, std::move(weak));
+ }
+ });
+
+ scheduled_updates_.push(
+ Update{requested_presentation_time, std::move(commands),
+ std::move(acquire_fence_set), std::move(release_events),
+ std::move(callback)});
+
return true;
}
void Session::ScheduleImagePipeUpdate(uint64_t presentation_time,
ImagePipePtr image_pipe) {
FXL_DCHECK(image_pipe);
- if (is_valid()) {
- scheduled_image_pipe_updates_.push(
- {presentation_time, std::move(image_pipe)});
+ scheduled_image_pipe_updates_.push(
+ {presentation_time, std::move(image_pipe)});
- session_context_.session_manager->ScheduleUpdateForSession(
- session_context_.update_scheduler, presentation_time, SessionPtr(this));
- }
+ session_context_.session_manager->ScheduleUpdateForSession(
+ session_context_.update_scheduler, presentation_time, GetWeakPtr());
}
-bool Session::ApplyScheduledUpdates(CommandContext* command_context,
- uint64_t presentation_time,
- uint64_t presentation_interval) {
+Session::ApplyUpdateResult Session::ApplyScheduledUpdates(
+ CommandContext* command_context, uint64_t presentation_time,
+ uint64_t presentation_interval) {
TRACE_DURATION("gfx", "Session::ApplyScheduledUpdates", "session_id", id_,
"session_debug_name", debug_name_, "time", presentation_time,
"interval", presentation_interval);
+ ApplyUpdateResult update_results{false, false};
+
if (presentation_time < last_presentation_time_) {
error_reporter_->ERROR()
<< "scenic_impl::gfx::Session: ApplyScheduledUpdates called with "
"presentation_time="
<< presentation_time << ", which is less than last_presentation_time_="
<< last_presentation_time_ << ".";
- return false;
+ update_results.success = false;
+ return update_results;
}
- bool needs_render = false;
while (!scheduled_updates_.empty() &&
scheduled_updates_.front().presentation_time <= presentation_time) {
if (!scheduled_updates_.front().acquire_fences->ready()) {
@@ -1584,7 +214,7 @@
}
if (ApplyUpdate(command_context,
std::move(scheduled_updates_.front().commands))) {
- needs_render = true;
+ update_results.needs_render = true;
auto info = fuchsia::images::PresentationInfo();
info.presentation_time = presentation_time;
info.presentation_interval = presentation_interval;
@@ -1611,14 +241,13 @@
FXL_LOG(WARNING) << "scenic_impl::gfx::Session::ApplyScheduledUpdates(): "
"An error was encountered while applying the update. "
"Initiating teardown.";
-
+ update_results.success = false;
scheduled_updates_ = {};
- BeginTearDown();
-
// Tearing down a session will very probably result in changes to
// the global scene-graph.
- return true;
+ update_results.needs_render = true;
+ return update_results;
}
}
@@ -1629,42 +258,36 @@
// The bool returned from Update() is 0 or 1, and needs_render is 0 or 1, so
// bitwise |= is used which doesn't short-circuit.
if (scheduled_image_pipe_updates_.top().image_pipe) {
- needs_render |= scheduled_image_pipe_updates_.top().image_pipe->Update(
- session_context_.release_fence_signaller, presentation_time,
- presentation_interval);
+ update_results.needs_render |=
+ scheduled_image_pipe_updates_.top().image_pipe->Update(
+ session_context_.release_fence_signaller, presentation_time,
+ presentation_interval);
}
scheduled_image_pipe_updates_.pop();
}
- return needs_render;
+ update_results.success = true;
+ return update_results;
}
void Session::EnqueueEvent(::fuchsia::ui::gfx::Event event) {
- if (!is_valid()) {
- return;
- }
event_reporter_->EnqueueEvent(std::move(event));
}
void Session::EnqueueEvent(::fuchsia::ui::input::InputEvent event) {
- if (!is_valid()) {
- return;
- }
event_reporter_->EnqueueEvent(std::move(event));
}
bool Session::ApplyUpdate(CommandContext* command_context,
std::vector<::fuchsia::ui::gfx::Command> commands) {
TRACE_DURATION("gfx", "Session::ApplyUpdate");
- if (is_valid()) {
- for (auto& command : commands) {
- if (!ApplyCommand(command_context, std::move(command))) {
- using ::operator<<; // From print_commands.h
- error_reporter_->ERROR() << "scenic_impl::gfx::Session::ApplyCommand() "
- "failed to apply Command: "
- << command;
- return false;
- }
+ for (auto& command : commands) {
+ if (!ApplyCommand(command_context, std::move(command))) {
+ using ::operator<<; // From print_commands.h
+ error_reporter_->ERROR() << "scenic_impl::gfx::Session::ApplyCommand() "
+ "failed to apply Command: "
+ << command;
+ return false;
}
}
return true;
@@ -1709,9 +332,5 @@
callback(WrapHits(layer_stack_hits));
}
-void Session::BeginTearDown() {
- session_context_.session_manager->TearDownSession(id());
-}
-
} // namespace gfx
} // namespace scenic_impl
diff --git a/lib/ui/gfx/engine/session.h b/lib/ui/gfx/engine/session.h
index 6107cd5..bd2baaa 100644
--- a/lib/ui/gfx/engine/session.h
+++ b/lib/ui/gfx/engine/session.h
@@ -10,11 +10,12 @@
#include <fuchsia/ui/gfx/cpp/fidl.h>
#include <fuchsia/ui/scenic/cpp/fidl.h>
+#include "garnet/lib/ui/gfx/engine/gfx_command_applier.h"
#include "garnet/lib/ui/gfx/engine/resource_map.h"
#include "garnet/lib/ui/gfx/engine/session_context.h"
+#include "garnet/lib/ui/gfx/engine/session_manager.h"
#include "garnet/lib/ui/gfx/id.h"
#include "garnet/lib/ui/gfx/resources/memory.h"
-#include "garnet/lib/ui/gfx/resources/resource.h"
#include "garnet/lib/ui/gfx/resources/resource_context.h"
#include "garnet/lib/ui/scenic/event_reporter.h"
#include "garnet/lib/ui/scenic/util/error_reporter.h"
@@ -26,27 +27,23 @@
namespace scenic_impl {
namespace gfx {
-class Image;
-using ImagePtr = ::fxl::RefPtr<Image>;
-
-class ImageBase;
-using ImageBasePtr = ::fxl::RefPtr<ImageBase>;
-
class ImagePipe;
-using ImagePipePtr = ::fxl::RefPtr<ImagePipe>;
-
-class Session;
-using SessionPtr = ::fxl::RefPtr<Session>;
+using ImagePipePtr = fxl::RefPtr<ImagePipe>;
class CommandContext;
class Engine;
class Resource;
-class SessionHandler;
-// TODO: use unsafe ref-counting for better performance (our architecture
-// guarantees that this is safe).
-class Session : public fxl::RefCountedThreadSafe<Session> {
+// gfx::Session is the internal endpoint of the scenic::Session channel.
+// It owns, and is responsible for, all graphics state on the channel
+class Session {
public:
+ // Return type for ApplyScheduledUpdate
+ struct ApplyUpdateResult {
+ bool success;
+ bool needs_render;
+ };
+
Session(SessionId id, SessionContext context,
EventReporter* event_reporter = EventReporter::Default(),
ErrorReporter* error_reporter = ErrorReporter::Default());
@@ -56,10 +53,17 @@
// successful, and false if the op is somehow invalid. In the latter case,
// the Session is left unchanged.
bool ApplyCommand(CommandContext* command_context,
- ::fuchsia::ui::gfx::Command command);
+ fuchsia::ui::gfx::Command command) {
+ return GfxCommandApplier::ApplyCommand(this, command_context,
+ std::move(command));
+ }
SessionId id() const { return id_; }
+ const fxl::WeakPtr<Session> GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+ }
+ const SessionContext& session_context() const { return session_context_; }
const ResourceContext& resource_context() const { return resource_context_; }
// Return the total number of existing resources associated with this Session.
@@ -71,9 +75,6 @@
// exist if it is referenced by other resources.
size_t GetMappedResourceCount() const { return resources_.size(); }
- // Session becomes invalid once TearDown is called.
- bool is_valid() const { return is_valid_; }
-
ErrorReporter* error_reporter() const; // Never nullptr.
EventReporter* event_reporter() const; // Never nullptr.
@@ -83,8 +84,8 @@
// applying them; they will later be applied by ApplyScheduledUpdates().
bool ScheduleUpdate(uint64_t presentation_time,
std::vector<::fuchsia::ui::gfx::Command> commands,
- ::std::vector<zx::event> acquire_fences,
- ::std::vector<zx::event> release_fences,
+ std::vector<zx::event> acquire_fences,
+ std::vector<zx::event> release_fences,
fuchsia::ui::scenic::Session::PresentCallback callback);
// Called by ImagePipe::PresentImage(). Stashes the arguments without
@@ -93,218 +94,32 @@
ImagePipePtr image_pipe);
// Called by Engine() when it is notified by the FrameScheduler that
- // a frame should be rendered for the specified |presentation_time|. Return
- // true if any updates were applied, and false otherwise.
- bool ApplyScheduledUpdates(CommandContext* command_context,
- uint64_t presentation_time,
- uint64_t presentation_interval);
+ // a frame should be rendered for the specified |presentation_time|.
+ // Returns ApplyUpdateResult.success as true if updates were successfully
+ // applied, false if updates failed to be applied.
+ // Returns ApplyUpdateResult.needs_render as true if any changes were
+ // applied, false if none were.
+ ApplyUpdateResult ApplyScheduledUpdates(CommandContext* command_context,
+ uint64_t presentation_time,
+ uint64_t presentation_interval);
// Convenience. Forwards an event to the EventReporter.
void EnqueueEvent(::fuchsia::ui::gfx::Event event);
void EnqueueEvent(::fuchsia::ui::input::InputEvent event);
// Called by SessionHandler::HitTest().
- void HitTest(uint32_t node_id, ::fuchsia::ui::gfx::vec3 ray_origin,
- ::fuchsia::ui::gfx::vec3 ray_direction,
+ void HitTest(uint32_t node_id, fuchsia::ui::gfx::vec3 ray_origin,
+ fuchsia::ui::gfx::vec3 ray_direction,
fuchsia::ui::scenic::Session::HitTestCallback callback);
// Called by SessionHandler::HitTestDeviceRay().
void HitTestDeviceRay(::fuchsia::ui::gfx::vec3 ray_origin,
- ::fuchsia::ui::gfx::vec3 ray_direction,
+ fuchsia::ui::gfx::vec3 ray_direction,
fuchsia::ui::scenic::Session::HitTestCallback callback);
void SetDebugName(const std::string& debug_name) { debug_name_ = debug_name; }
- protected:
- friend class SessionHandler;
- // Called only by SessionHandler. Use BeginTearDown() instead when you need to
- // teardown from within Session. Virtual to allow test subclasses to override.
- //
- // The chain of events is:
- // Session::BeginTearDown or SessionHandler::BeginTearDown
- // => Engine::TearDownSession
- // => SessionHandler::TearDown
- // => Session::TearDown
- //
- // We are guaranteed that by the time TearDown() is closed, SessionHandler
- // has destroyed the channel to this session.
- virtual void TearDown();
-
private:
- // Called internally to initiate teardown.
- void BeginTearDown();
-
- // Cmderation application functions, called by ApplyCommand().
- bool ApplyCreateResourceCmd(CommandContext* command_context,
- ::fuchsia::ui::gfx::CreateResourceCmd command);
- bool ApplyReleaseResourceCmd(::fuchsia::ui::gfx::ReleaseResourceCmd command);
- bool ApplyExportResourceCmd(::fuchsia::ui::gfx::ExportResourceCmd command);
- bool ApplyImportResourceCmd(::fuchsia::ui::gfx::ImportResourceCmd command);
- bool ApplyAddChildCmd(::fuchsia::ui::gfx::AddChildCmd command);
- bool ApplyAddPartCmd(::fuchsia::ui::gfx::AddPartCmd command);
- bool ApplyDetachCmd(::fuchsia::ui::gfx::DetachCmd command);
- bool ApplyDetachChildrenCmd(::fuchsia::ui::gfx::DetachChildrenCmd command);
- bool ApplySetTagCmd(::fuchsia::ui::gfx::SetTagCmd command);
- bool ApplySetTranslationCmd(::fuchsia::ui::gfx::SetTranslationCmd command);
- bool ApplySetScaleCmd(::fuchsia::ui::gfx::SetScaleCmd command);
- bool ApplySetRotationCmd(::fuchsia::ui::gfx::SetRotationCmd command);
- bool ApplySetAnchorCmd(::fuchsia::ui::gfx::SetAnchorCmd command);
- bool ApplySetSizeCmd(::fuchsia::ui::gfx::SetSizeCmd command);
- bool ApplySetOpacityCmd(::fuchsia::ui::gfx::SetOpacityCmd command);
- bool ApplySendSizeChangeHintCmd(
- ::fuchsia::ui::gfx::SendSizeChangeHintCmdHACK command);
- bool ApplySetShapeCmd(::fuchsia::ui::gfx::SetShapeCmd command);
- bool ApplySetMaterialCmd(::fuchsia::ui::gfx::SetMaterialCmd command);
- bool ApplySetClipCmd(::fuchsia::ui::gfx::SetClipCmd command);
- bool ApplySetViewPropertiesCmd(
- ::fuchsia::ui::gfx::SetViewPropertiesCmd command);
- bool ApplySetHitTestBehaviorCmd(
- ::fuchsia::ui::gfx::SetHitTestBehaviorCmd command);
- bool ApplySetCameraCmd(::fuchsia::ui::gfx::SetCameraCmd command);
- bool ApplySetCameraTransformCmd(
- ::fuchsia::ui::gfx::SetCameraTransformCmd command);
- bool ApplySetCameraProjectionCmd(
- ::fuchsia::ui::gfx::SetCameraProjectionCmd command);
- bool ApplySetStereoCameraProjectionCmd(
- ::fuchsia::ui::gfx::SetStereoCameraProjectionCmd command);
- bool ApplySetCameraPoseBufferCmd(
- ::fuchsia::ui::gfx::SetCameraPoseBufferCmd command);
- bool ApplySetLightColorCmd(::fuchsia::ui::gfx::SetLightColorCmd command);
- bool ApplySetLightDirectionCmd(
- ::fuchsia::ui::gfx::SetLightDirectionCmd command);
- bool ApplyAddLightCmd(::fuchsia::ui::gfx::AddLightCmd command);
- bool ApplyDetachLightCmd(::fuchsia::ui::gfx::DetachLightCmd command);
- bool ApplyDetachLightsCmd(::fuchsia::ui::gfx::DetachLightsCmd command);
- bool ApplySetTextureCmd(::fuchsia::ui::gfx::SetTextureCmd command);
- bool ApplySetColorCmd(::fuchsia::ui::gfx::SetColorCmd command);
- bool ApplyBindMeshBuffersCmd(::fuchsia::ui::gfx::BindMeshBuffersCmd command);
- bool ApplyAddLayerCmd(::fuchsia::ui::gfx::AddLayerCmd command);
- bool ApplyRemoveLayerCmd(::fuchsia::ui::gfx::RemoveLayerCmd command);
- bool ApplyRemoveAllLayersCmd(::fuchsia::ui::gfx::RemoveAllLayersCmd command);
- bool ApplySetLayerStackCmd(::fuchsia::ui::gfx::SetLayerStackCmd command);
- bool ApplySetRendererCmd(::fuchsia::ui::gfx::SetRendererCmd command);
- bool ApplySetRendererParamCmd(
- ::fuchsia::ui::gfx::SetRendererParamCmd command);
- bool ApplySetEventMaskCmd(::fuchsia::ui::gfx::SetEventMaskCmd command);
- bool ApplySetLabelCmd(::fuchsia::ui::gfx::SetLabelCmd command);
- bool ApplySetDisableClippingCmd(
- ::fuchsia::ui::gfx::SetDisableClippingCmd command);
-
- // Resource creation functions, called by ApplyCreateResourceCmd().
- bool ApplyCreateMemory(ResourceId id, ::fuchsia::ui::gfx::MemoryArgs args);
- bool ApplyCreateImage(ResourceId id, ::fuchsia::ui::gfx::ImageArgs args);
- bool ApplyCreateImagePipe(ResourceId id,
- ::fuchsia::ui::gfx::ImagePipeArgs args);
- bool ApplyCreateBuffer(ResourceId id, ::fuchsia::ui::gfx::BufferArgs args);
- bool ApplyCreateScene(ResourceId id, ::fuchsia::ui::gfx::SceneArgs args);
- bool ApplyCreateCamera(ResourceId id, ::fuchsia::ui::gfx::CameraArgs args);
- bool ApplyCreateStereoCamera(ResourceId id,
- ::fuchsia::ui::gfx::StereoCameraArgs args);
- bool ApplyCreateRenderer(ResourceId id,
- ::fuchsia::ui::gfx::RendererArgs args);
- bool ApplyCreateAmbientLight(ResourceId id,
- ::fuchsia::ui::gfx::AmbientLightArgs args);
- bool ApplyCreateDirectionalLight(
- ResourceId id, ::fuchsia::ui::gfx::DirectionalLightArgs args);
- bool ApplyCreateRectangle(ResourceId id,
- ::fuchsia::ui::gfx::RectangleArgs args);
- bool ApplyCreateRoundedRectangle(
- CommandContext* command_context, ResourceId id,
- ::fuchsia::ui::gfx::RoundedRectangleArgs args);
- bool ApplyCreateCircle(ResourceId id, ::fuchsia::ui::gfx::CircleArgs args);
- bool ApplyCreateMesh(ResourceId id, ::fuchsia::ui::gfx::MeshArgs args);
- bool ApplyCreateMaterial(ResourceId id,
- ::fuchsia::ui::gfx::MaterialArgs args);
- bool ApplyCreateView(ResourceId id, ::fuchsia::ui::gfx::ViewArgs args);
- bool ApplyCreateViewHolder(ResourceId id,
- ::fuchsia::ui::gfx::ViewHolderArgs args);
- bool ApplyCreateClipNode(ResourceId id,
- ::fuchsia::ui::gfx::ClipNodeArgs args);
- bool ApplyCreateEntityNode(ResourceId id,
- ::fuchsia::ui::gfx::EntityNodeArgs args);
- bool ApplyCreateOpacityNode(ResourceId id,
- ::fuchsia::ui::gfx::OpacityNodeArgs args);
- bool ApplyCreateShapeNode(ResourceId id,
- ::fuchsia::ui::gfx::ShapeNodeArgs args);
- bool ApplyCreateCompositor(ResourceId id,
- ::fuchsia::ui::gfx::CompositorArgs args);
- bool ApplyCreateDisplayCompositor(
- ResourceId id, ::fuchsia::ui::gfx::DisplayCompositorArgs args);
- bool ApplyCreateImagePipeCompositor(
- ResourceId id, ::fuchsia::ui::gfx::ImagePipeCompositorArgs args);
- bool ApplyCreateLayerStack(ResourceId id,
- ::fuchsia::ui::gfx::LayerStackArgs args);
- bool ApplyCreateLayer(ResourceId id, ::fuchsia::ui::gfx::LayerArgs args);
- bool ApplyCreateVariable(ResourceId id,
- ::fuchsia::ui::gfx::VariableArgs args);
- bool ApplyTakeSnapshotCmdHACK(
- ::fuchsia::ui::gfx::TakeSnapshotCmdHACK command);
-
- // Actually create resources.
- ResourcePtr CreateMemory(ResourceId id, ::fuchsia::ui::gfx::MemoryArgs args);
- ResourcePtr CreateImage(ResourceId id, MemoryPtr memory,
- ::fuchsia::ui::gfx::ImageArgs args);
- ResourcePtr CreateBuffer(ResourceId id, MemoryPtr memory,
- uint32_t memory_offset, uint32_t num_bytes);
-
- ResourcePtr CreateScene(ResourceId id, ::fuchsia::ui::gfx::SceneArgs args);
- ResourcePtr CreateCamera(ResourceId id, ::fuchsia::ui::gfx::CameraArgs args);
- ResourcePtr CreateStereoCamera(ResourceId id,
- ::fuchsia::ui::gfx::StereoCameraArgs args);
- ResourcePtr CreateRenderer(ResourceId id,
- ::fuchsia::ui::gfx::RendererArgs args);
-
- ResourcePtr CreateAmbientLight(ResourceId id);
- ResourcePtr CreateDirectionalLight(ResourceId id);
-
- ResourcePtr CreateView(ResourceId id, ::fuchsia::ui::gfx::ViewArgs args);
- ResourcePtr CreateViewHolder(ResourceId id,
- ::fuchsia::ui::gfx::ViewHolderArgs args);
- ResourcePtr CreateClipNode(ResourceId id,
- ::fuchsia::ui::gfx::ClipNodeArgs args);
- ResourcePtr CreateEntityNode(ResourceId id,
- ::fuchsia::ui::gfx::EntityNodeArgs args);
- ResourcePtr CreateOpacityNode(ResourceId id,
- ::fuchsia::ui::gfx::OpacityNodeArgs args);
- ResourcePtr CreateShapeNode(ResourceId id,
- ::fuchsia::ui::gfx::ShapeNodeArgs args);
-
- ResourcePtr CreateCompositor(ResourceId id,
- ::fuchsia::ui::gfx::CompositorArgs args);
- ResourcePtr CreateDisplayCompositor(
- ResourceId id, ::fuchsia::ui::gfx::DisplayCompositorArgs args);
- ResourcePtr CreateImagePipeCompositor(
- ResourceId id, ::fuchsia::ui::gfx::ImagePipeCompositorArgs args);
- ResourcePtr CreateLayerStack(ResourceId id,
- ::fuchsia::ui::gfx::LayerStackArgs args);
- ResourcePtr CreateLayer(ResourceId id, ::fuchsia::ui::gfx::LayerArgs args);
- ResourcePtr CreateCircle(ResourceId id, float initial_radius);
- ResourcePtr CreateRectangle(ResourceId id, float width, float height);
- ResourcePtr CreateRoundedRectangle(CommandContext* command_context,
- ResourceId id, float width, float height,
- float top_left_radius,
- float top_right_radius,
- float bottom_right_radius,
- float bottom_left_radius);
- ResourcePtr CreateMesh(ResourceId id);
- ResourcePtr CreateMaterial(ResourceId id);
- ResourcePtr CreateVariable(ResourceId id,
- ::fuchsia::ui::gfx::VariableArgs args);
-
- // Return false and log an error if the value is not of the expected type.
- // NOTE: although failure does not halt execution of the program, it does
- // indicate client error, and will be used by the caller to tear down the
- // Session.
- bool AssertValueIsOfType(const ::fuchsia::ui::gfx::Value& value,
- const ::fuchsia::ui::gfx::Value::Tag* tags,
- size_t tag_count);
- template <size_t N>
- bool AssertValueIsOfType(
- const ::fuchsia::ui::gfx::Value& value,
- const std::array<::fuchsia::ui::gfx::Value::Tag, N>& tags) {
- return AssertValueIsOfType(value, tags.data(), N);
- }
-
friend class Resource;
void IncrementResourceCount() { ++resource_count_; }
void DecrementResourceCount() { --resource_count_; }
@@ -314,7 +129,7 @@
std::vector<::fuchsia::ui::gfx::Command> commands;
std::unique_ptr<escher::FenceSetListener> acquire_fences;
- ::std::vector<zx::event> release_fences;
+ std::vector<zx::event> release_fences;
// Callback to report when the update has been applied in response to
// an invocation of |Session.Present()|.
@@ -323,7 +138,7 @@
bool ApplyUpdate(CommandContext* command_context,
std::vector<::fuchsia::ui::gfx::Command> commands);
std::queue<Update> scheduled_updates_;
- ::std::vector<zx::event> fences_to_release_on_next_update_;
+ std::vector<zx::event> fences_to_release_on_next_update_;
uint64_t last_applied_update_presentation_time_ = 0;
uint64_t last_presentation_time_ = 0;
@@ -350,11 +165,8 @@
// Resources; their lifecycle must exceed that of the Resources.
SessionContext session_context_;
ResourceContext resource_context_;
-
ResourceMap resources_;
-
size_t resource_count_ = 0;
- bool is_valid_ = true;
fxl::WeakPtrFactory<Session> weak_factory_; // must be last
};
diff --git a/lib/ui/gfx/engine/session_handler.cc b/lib/ui/gfx/engine/session_handler.cc
index 2ab7b52..1406226 100644
--- a/lib/ui/gfx/engine/session_handler.cc
+++ b/lib/ui/gfx/engine/session_handler.cc
@@ -4,6 +4,8 @@
#include "garnet/lib/ui/gfx/engine/session_handler.h"
+#include <memory>
+
#include "garnet/lib/ui/scenic/session.h"
#include "lib/ui/scenic/cpp/commands.h"
@@ -20,15 +22,18 @@
session_manager_(session_manager),
event_reporter_(event_reporter),
error_reporter_(error_reporter),
- session_(::fxl::MakeRefCounted<scenic_impl::gfx::Session>(
- session_id, std::move(session_context), event_reporter,
- error_reporter)) {
+ session_(std::make_unique<Session>(session_id, std::move(session_context),
+ event_reporter, error_reporter)) {
FXL_DCHECK(session_manager_);
}
-SessionHandler::~SessionHandler() {
- TearDown();
- session_manager_->RemoveSession(session_->id());
+SessionHandler::~SessionHandler() { CleanUp(); }
+
+void SessionHandler::CleanUp() {
+ if (session_.get() != nullptr) {
+ session_manager_->RemoveSessionHandler(session_->id());
+ session_.reset();
+ }
}
void SessionHandler::Present(
@@ -40,8 +45,9 @@
std::move(acquire_fences), std::move(release_fences),
std::move(callback))) {
BeginTearDown();
+ } else {
+ buffered_commands_.clear();
}
- buffered_commands_.clear();
}
void SessionHandler::HitTest(
@@ -65,17 +71,9 @@
}
void SessionHandler::BeginTearDown() {
- session_manager_->TearDownSession(session_->id());
- FXL_DCHECK(!session_->is_valid());
-}
-
-void SessionHandler::TearDown() {
- session_->TearDown();
-
- // Close the parent Mozart session.
- if (context() && context()->session()) {
- context()->scenic()->CloseSession(context()->session());
- }
+ // Since this is essentially a self destruct
+ // call, it's safest not call anything after this
+ context()->KillSession();
}
} // namespace gfx
diff --git a/lib/ui/gfx/engine/session_handler.h b/lib/ui/gfx/engine/session_handler.h
index e694996..30d136f 100644
--- a/lib/ui/gfx/engine/session_handler.h
+++ b/lib/ui/gfx/engine/session_handler.h
@@ -5,13 +5,13 @@
#ifndef GARNET_LIB_UI_GFX_ENGINE_SESSION_HANDLER_H_
#define GARNET_LIB_UI_GFX_ENGINE_SESSION_HANDLER_H_
+#include "garnet/lib/ui/gfx/engine/session.h"
#include "lib/fidl/cpp/binding_set.h"
#include "lib/fidl/cpp/interface_ptr_set.h"
#include "lib/fxl/tasks/task_runner.h"
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include "garnet/lib/ui/gfx/engine/engine.h"
-#include "garnet/lib/ui/gfx/engine/session.h"
#include "garnet/lib/ui/scenic/command_dispatcher.h"
#include "garnet/lib/ui/scenic/event_reporter.h"
#include "garnet/lib/ui/scenic/util/error_reporter.h"
@@ -66,19 +66,21 @@
private:
friend class SessionManager;
- // Called by |binding_| when the connection closes. Must be invoked within
- // the SessionHandler MessageLoop.
+ // Called to initiate a session crash when an update fails.
+ // Requests the destruction of client fidl session, which
+ // then triggers the actual destruction of the SessionHandler
void BeginTearDown();
- // Called only by Engine. Use BeginTearDown() instead when you need to
- // teardown from within SessionHandler.
- void TearDown();
+ // Remove SessionHandler reference from SessionManager
+ // and destroy gfx::Session
+ void CleanUp();
SessionManager* const session_manager_;
EventReporter* const event_reporter_;
ErrorReporter* const error_reporter_;
- scenic_impl::gfx::SessionPtr session_;
+
+ std::unique_ptr<Session> session_;
// TODO(SCN-710): We reallocate this everytime we std::move it into
// ScheduleUpdate(). The bug has some ideas about how to do better.
diff --git a/lib/ui/gfx/engine/session_manager.cc b/lib/ui/gfx/engine/session_manager.cc
index 1e915e7..dff2a3b 100644
--- a/lib/ui/gfx/engine/session_manager.cc
+++ b/lib/ui/gfx/engine/session_manager.cc
@@ -28,9 +28,9 @@
}
}
-SessionHandler* SessionManager::FindSession(SessionId id) {
- auto it = session_manager_.find(id);
- if (it != session_manager_.end()) {
+SessionHandler* SessionManager::FindSessionHandler(SessionId id) {
+ auto it = session_handlers_.find(id);
+ if (it != session_handlers_.end()) {
return it->second;
}
return nullptr;
@@ -51,18 +51,23 @@
scenic_impl::Session* session = context.session();
auto handler = CreateSessionHandler(std::move(context), engine, session_id,
session, session->error_reporter());
- session_manager_.insert({session_id, handler.get()});
- ++session_count_;
-
+ InsertSessionHandler(session_id, handler.get());
return handler;
}
-void SessionManager::ScheduleUpdateForSession(UpdateScheduler* update_scheduler,
- uint64_t presentation_time,
- fxl::RefPtr<Session> session) {
+void SessionManager::InsertSessionHandler(SessionId session_id,
+ SessionHandler* session_handler) {
+ FXL_DCHECK(session_handlers_.find(session_id) == session_handlers_.end());
+ session_handlers_.insert({session_id, session_handler});
+ ++session_count_;
+}
+
+void SessionManager::ScheduleUpdateForSession(
+ UpdateScheduler* update_scheduler, uint64_t presentation_time,
+ fxl::WeakPtr<scenic_impl::gfx::Session> session) {
FXL_DCHECK(update_scheduler);
- if (session->is_valid()) {
- updatable_sessions_.insert({presentation_time, std::move(session)});
+ if (session) {
+ updatable_sessions_.push({presentation_time, std::move(session)});
update_scheduler->ScheduleUpdate(presentation_time);
}
}
@@ -75,14 +80,23 @@
bool needs_render = false;
while (!updatable_sessions_.empty()) {
- auto top = updatable_sessions_.begin();
- if (top->first > presentation_time)
+ auto& top = updatable_sessions_.top();
+ if (top.first > presentation_time)
break;
- auto session = std::move(top->second);
- updatable_sessions_.erase(top);
- if (session) {
- needs_render |= session->ApplyScheduledUpdates(
+ auto session = std::move(top.second);
+ updatable_sessions_.pop();
+ if (session.get() != nullptr) {
+ auto update_results = session->ApplyScheduledUpdates(
command_context, presentation_time, presentation_interval);
+
+ needs_render |= update_results.needs_render;
+
+ // If update fails, kill the entire client session
+ if (!update_results.success) {
+ auto session_handler = FindSessionHandler(session->id());
+ FXL_DCHECK(session_handler);
+ session_handler->BeginTearDown();
+ }
} else {
// Corresponds to a call to ScheduleUpdate(), which always triggers a
// render.
@@ -92,26 +106,10 @@
return needs_render;
}
-void SessionManager::TearDownSession(SessionId id) {
- auto it = session_manager_.find(id);
- FXL_DCHECK(it != session_manager_.end());
- if (it != session_manager_.end()) {
- SessionHandler* handler = std::move(it->second);
- session_manager_.erase(it);
- FXL_DCHECK(session_count_ > 0);
- --session_count_;
-
- // Don't destroy handler immediately, since it may be the one calling
- // TearDownSession().
- async::PostTask(async_get_default_dispatcher(),
- [handler] { handler->TearDown(); });
- }
-}
-
-void SessionManager::RemoveSession(SessionId id) {
- auto it = session_manager_.find(id);
- if (it != session_manager_.end()) {
- session_manager_.erase(it);
+void SessionManager::RemoveSessionHandler(SessionId id) {
+ auto it = session_handlers_.find(id);
+ if (it != session_handlers_.end()) {
+ session_handlers_.erase(it);
FXL_DCHECK(session_count_ > 0);
--session_count_;
}
diff --git a/lib/ui/gfx/engine/session_manager.h b/lib/ui/gfx/engine/session_manager.h
index 766de85..9fd4475 100644
--- a/lib/ui/gfx/engine/session_manager.h
+++ b/lib/ui/gfx/engine/session_manager.h
@@ -8,6 +8,7 @@
#include <set>
#include <unordered_map>
+#include "garnet/lib/ui/gfx/engine/session.h"
#include "garnet/lib/ui/scenic/command_dispatcher.h"
#include "lib/escher/renderer/batch_gpu_uploader.h"
@@ -20,9 +21,9 @@
namespace gfx {
using SessionId = ::scenic_impl::SessionId;
+using PresentationTime = uint64_t;
class SessionHandler;
-class Session;
class Engine;
class UpdateScheduler;
@@ -55,7 +56,7 @@
virtual ~SessionManager() = default;
// Finds the session handler corresponding to the given id.
- SessionHandler* FindSession(SessionId id);
+ SessionHandler* FindSessionHandler(SessionId id);
size_t GetSessionCount() { return session_count_; }
@@ -66,9 +67,9 @@
// Tell the UpdateScheduler to schedule a frame, and remember the Session so
// that we can tell it to apply updates in ApplyScheduledSessionUpdates().
- void ScheduleUpdateForSession(UpdateScheduler* update_scheduler,
- uint64_t presentation_time,
- fxl::RefPtr<Session> session);
+ void ScheduleUpdateForSession(
+ UpdateScheduler* update_scheduler, uint64_t presentation_time,
+ fxl::WeakPtr<scenic_impl::gfx::Session> session);
// Executes updates that are schedule up to and including a given presentation
// time. Returns true if rendering is needed.
@@ -76,29 +77,45 @@
uint64_t presentation_time,
uint64_t presentation_interval);
+ protected:
+ // Protected for testing subclass
+ void InsertSessionHandler(SessionId session_id,
+ SessionHandler* session_handler);
+
private:
- friend class Session;
friend class SessionHandler;
- // Destroys the session with the given id.
- void TearDownSession(SessionId id);
+ // Used to compare presentation times so that the priority_queue acts as a min
+ // heap, placing the earliest PresentationTime at the top
+ class UpdatableSessionsComparator {
+ public:
+ bool operator()(
+ std::pair<PresentationTime, fxl::WeakPtr<Session>> updatable_session1,
+ std::pair<PresentationTime, fxl::WeakPtr<Session>> updatable_session2) {
+ return updatable_session1.first > updatable_session2.first;
+ }
+ };
- // Removes the session from the session_manager_ map. We assume that the
- // SessionHandler has already taken care of itself and its Session.
- void RemoveSession(SessionId id);
+ // Removes the SessionHandler from the session_handlers_ map. We assume that
+ // the SessionHandler has already taken care of itself and its Session.
+ void RemoveSessionHandler(SessionId id);
virtual std::unique_ptr<SessionHandler> CreateSessionHandler(
CommandDispatcherContext context, Engine* engine, SessionId session_id,
EventReporter* event_reporter, ErrorReporter* error_reporter) const;
// Map of all the sessions.
- std::unordered_map<SessionId, SessionHandler*> session_manager_;
+ std::unordered_map<SessionId, SessionHandler*> session_handlers_;
size_t session_count_ = 0;
SessionId next_session_id_ = 1;
// Lists all Session that have updates to apply, sorted by the earliest
// requested presentation time of each update.
- std::set<std::pair<uint64_t, fxl::RefPtr<Session>>> updatable_sessions_;
+ std::priority_queue<
+ std::pair<PresentationTime, fxl::WeakPtr<Session>>,
+ std::vector<std::pair<PresentationTime, fxl::WeakPtr<Session>>>,
+ UpdatableSessionsComparator>
+ updatable_sessions_;
};
} // namespace gfx
diff --git a/lib/ui/gfx/gfx_system.cc b/lib/ui/gfx/gfx_system.cc
index f05b1e0..ffc3a7d 100644
--- a/lib/ui/gfx/gfx_system.cc
+++ b/lib/ui/gfx/gfx_system.cc
@@ -323,7 +323,8 @@
}
gfx::Session* GfxSystem::GetSession(SessionId session_id) const {
- SessionHandler* handler = engine_->session_manager()->FindSession(session_id);
+ SessionHandler* handler =
+ engine_->session_manager()->FindSessionHandler(session_id);
return handler ? handler->session() : nullptr;
}
diff --git a/lib/ui/gfx/tests/BUILD.gn b/lib/ui/gfx/tests/BUILD.gn
index b9903b1..1f4a79f 100644
--- a/lib/ui/gfx/tests/BUILD.gn
+++ b/lib/ui/gfx/tests/BUILD.gn
@@ -20,6 +20,8 @@
"gfx_test.h",
"mocks.cc",
"mocks.h",
+ "session_handler_test.cc",
+ "session_handler_test.h",
"session_test.cc",
"session_test.h",
"vk_session_test.cc",
@@ -60,6 +62,7 @@
sources = [
"escher_vulkan_smoke_test.cc",
"event_timestamper_unittest.cc",
+ "gfx_command_applier_unittest.cc",
"hardware_layer_assignment_unittest.cc",
"hittest_global_unittest.cc",
"hittest_unittest.cc",
@@ -72,6 +75,7 @@
"resource_linker_unittest.cc",
"run_all_unittests.cc",
"scene_graph_unittest.cc",
+ "session_handler_unittest.cc",
"session_unittest.cc",
"shape_unittest.cc",
"size_change_hint_unittest.cc",
diff --git a/lib/ui/gfx/tests/gfx_apptest.cc b/lib/ui/gfx/tests/gfx_apptest.cc
index 6321bff..97351e1 100644
--- a/lib/ui/gfx/tests/gfx_apptest.cc
+++ b/lib/ui/gfx/tests/gfx_apptest.cc
@@ -66,9 +66,9 @@
RunLoopUntilIdle();
EXPECT_EQ(1U, scenic()->num_sessions());
auto handler = static_cast<SessionHandlerForTest*>(
- gfx_system()->engine()->session_manager()->FindSession(1));
+ gfx_system()->engine()->session_manager()->FindSessionHandler(1));
{
- ::std::vector<fuchsia::ui::scenic::Command> commands;
+ std::vector<fuchsia::ui::scenic::Command> commands;
commands.push_back(scenic::NewCommand(scenic::NewCreateCircleCmd(1, 50.f)));
commands.push_back(scenic::NewCommand(scenic::NewCreateCircleCmd(2, 25.f)));
@@ -77,22 +77,20 @@
RunLoopUntilIdle();
EXPECT_EQ(2u, handler->command_count());
// Create release fences
- ::std::vector<zx::event> release_fences = CreateEventArray(2);
+ std::vector<zx::event> release_fences = CreateEventArray(2);
zx::event release_fence1 = CopyEvent(release_fences.at(0));
zx::event release_fence2 = CopyEvent(release_fences.at(1));
EXPECT_FALSE(IsFenceSignalled(release_fence1));
EXPECT_FALSE(IsFenceSignalled(release_fence2));
// Call Present with release fences.
- session->Present(0u, std::vector<zx::event>(),
- std::move(release_fences),
+ session->Present(0u, std::vector<zx::event>(), std::move(release_fences),
[](fuchsia::images::PresentationInfo info) {});
RunLoopUntilIdle();
EXPECT_EQ(1u, handler->present_count());
EXPECT_FALSE(IsFenceSignalled(release_fence1));
EXPECT_FALSE(IsFenceSignalled(release_fence2));
// Call Present again with no release fences.
- session->Present(0u, ::std::vector<zx::event>(),
- ::std::vector<zx::event>(),
+ session->Present(0u, std::vector<zx::event>(), std::vector<zx::event>(),
[](fuchsia::images::PresentationInfo info) {});
RunLoopUntilIdle();
EXPECT_EQ(2u, handler->present_count());
@@ -109,9 +107,9 @@
RunLoopUntilIdle();
EXPECT_EQ(1U, scenic()->num_sessions());
auto handler = static_cast<SessionHandlerForTest*>(
- gfx_system()->engine()->session_manager()->FindSession(1));
+ gfx_system()->engine()->session_manager()->FindSessionHandler(1));
{
- ::std::vector<fuchsia::ui::scenic::Command> commands;
+ std::vector<fuchsia::ui::scenic::Command> commands;
commands.push_back(scenic::NewCommand(scenic::NewCreateCircleCmd(1, 50.f)));
commands.push_back(scenic::NewCommand(scenic::NewCreateCircleCmd(2, 25.f)));
@@ -124,9 +122,9 @@
ASSERT_EQ(ZX_OK, zx::event::create(0, &acquire_fence));
zx::event release_fence;
ASSERT_EQ(ZX_OK, zx::event::create(0, &release_fence));
- ::std::vector<zx::event> acquire_fences;
+ std::vector<zx::event> acquire_fences;
acquire_fences.push_back(CopyEvent(acquire_fence));
- ::std::vector<zx::event> release_fences;
+ std::vector<zx::event> release_fences;
release_fences.push_back(CopyEvent(release_fence));
// Call Present with both the acquire and release fences.
session->Present(0u, std::move(acquire_fences), std::move(release_fences),
@@ -135,8 +133,7 @@
EXPECT_EQ(1u, handler->present_count());
EXPECT_FALSE(IsFenceSignalled(release_fence));
// Call Present again with no fences.
- session->Present(0u, ::std::vector<zx::event>(),
- ::std::vector<zx::event>(),
+ session->Present(0u, std::vector<zx::event>(), std::vector<zx::event>(),
[](fuchsia::images::PresentationInfo info) {});
RunLoopUntilIdle();
EXPECT_EQ(2u, handler->present_count());
diff --git a/lib/ui/gfx/tests/gfx_command_applier_unittest.cc b/lib/ui/gfx/tests/gfx_command_applier_unittest.cc
new file mode 100644
index 0000000..4f7b557
--- /dev/null
+++ b/lib/ui/gfx/tests/gfx_command_applier_unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2019 The Fuchsia 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 "garnet/lib/ui/gfx/engine/gfx_command_applier.h"
+#include "garnet/lib/ui/gfx/tests/session_test.h"
+
+#include "lib/ui/scenic/cpp/commands.h"
+
+#include "gtest/gtest.h"
+
+namespace scenic_impl {
+namespace gfx {
+namespace test {
+
+using GfxCommandApplierTest = SessionTest;
+
+TEST_F(GfxCommandApplierTest, NewCreateEntityNodeCmd) {
+ CommandContext empty_command_context(nullptr);
+
+ // Valid id passes
+ EXPECT_TRUE(GfxCommandApplier::ApplyCommand(
+ session_.get(), &empty_command_context,
+ scenic::NewCreateEntityNodeCmd(/*id*/ 1)));
+
+ // Invalid id fails
+ EXPECT_FALSE(GfxCommandApplier::ApplyCommand(
+ session_.get(), &empty_command_context,
+ scenic::NewCreateEntityNodeCmd(/*id*/ 0)));
+}
+
+TEST_F(GfxCommandApplierTest, EraseResource) {
+ CommandContext empty_command_context(nullptr);
+ EXPECT_TRUE(GfxCommandApplier::ApplyCommand(
+ session_.get(), &empty_command_context,
+ scenic::NewCreateEntityNodeCmd(/*id*/ 3)));
+ // Erasing non-existent resource fails
+ EXPECT_FALSE(
+ GfxCommandApplier::ApplyCommand(session_.get(), &empty_command_context,
+ scenic::NewReleaseResourceCmd(/*id*/ 2)));
+
+ // Erasing existing resource passes
+ EXPECT_TRUE(
+ GfxCommandApplier::ApplyCommand(session_.get(), &empty_command_context,
+ scenic::NewReleaseResourceCmd(/*id*/ 3)));
+}
+
+TEST_F(GfxCommandApplierTest, SeparateSessionsAreIndependent) {
+ auto session2 = CreateSession();
+
+ CommandContext empty_command_context(nullptr);
+
+ EXPECT_TRUE(GfxCommandApplier::ApplyCommand(
+ session_.get(), &empty_command_context,
+ scenic::NewCreateEntityNodeCmd(/*id*/ 3)));
+ EXPECT_FALSE(
+ GfxCommandApplier::ApplyCommand(session2.get(), &empty_command_context,
+ scenic::NewReleaseResourceCmd(/*id*/ 3)));
+ EXPECT_TRUE(GfxCommandApplier::ApplyCommand(
+ session2.get(), &empty_command_context,
+ scenic::NewCreateEntityNodeCmd(/*id*/ 3)));
+ EXPECT_TRUE(
+ GfxCommandApplier::ApplyCommand(session_.get(), &empty_command_context,
+ scenic::NewReleaseResourceCmd(/*id*/ 3)));
+ EXPECT_TRUE(
+ GfxCommandApplier::ApplyCommand(session2.get(), &empty_command_context,
+ scenic::NewReleaseResourceCmd(/*id*/ 3)));
+}
+
+} // namespace test
+} // namespace gfx
+} // namespace scenic_impl
diff --git a/lib/ui/gfx/tests/hittest_global_unittest.cc b/lib/ui/gfx/tests/hittest_global_unittest.cc
index 1e4d3dc..8154a50 100644
--- a/lib/ui/gfx/tests/hittest_global_unittest.cc
+++ b/lib/ui/gfx/tests/hittest_global_unittest.cc
@@ -46,14 +46,10 @@
class CustomSession {
public:
CustomSession(SessionId id, SessionContext session_context) {
- session_ =
- fxl::MakeRefCounted<SessionForTest>(id, std::move(session_context));
+ session_ = std::make_unique<SessionForTest>(id, std::move(session_context));
}
- ~CustomSession() {
- session_->TearDown();
- session_ = nullptr;
- }
+ ~CustomSession() {}
void Apply(::fuchsia::ui::gfx::Command command) {
CommandContext empty_command_context(nullptr);
@@ -63,7 +59,7 @@
}
private:
- fxl::RefPtr<SessionForTest> session_;
+ std::unique_ptr<SessionForTest> session_;
};
// Loop fixture provides dispatcher for Engine's EventTimestamper.
diff --git a/lib/ui/gfx/tests/image_pipe_unittest.cc b/lib/ui/gfx/tests/image_pipe_unittest.cc
index 75a842f..e52a2d4 100644
--- a/lib/ui/gfx/tests/image_pipe_unittest.cc
+++ b/lib/ui/gfx/tests/image_pipe_unittest.cc
@@ -39,7 +39,7 @@
public:
ImagePipeTest() : escher::ResourceManager(escher::EscherWeakPtr()) {}
- fxl::RefPtr<SessionForTest> CreateSession() override {
+ std::unique_ptr<SessionForTest> CreateSession() override {
SessionContext session_context = CreateBarebonesSessionContext();
command_buffer_sequencer_ =
@@ -51,8 +51,8 @@
session_context.release_fence_signaller =
mock_release_fence_signaller_.get();
- return fxl::MakeRefCounted<SessionForTest>(1, std::move(session_context),
- this, error_reporter());
+ return std::make_unique<SessionForTest>(1, std::move(session_context), this,
+ error_reporter());
}
void OnReceiveOwnable(std::unique_ptr<escher::Resource> resource) override {}
@@ -364,8 +364,10 @@
imageIdB, std::move(image_info_b), CopyVmo(gradient_b->vmo()), 0,
GetVmoSize(gradient_b->vmo()), fuchsia::images::MemoryType::HOST_MEMORY);
- image_pipe->PresentImage(imageIdA, 0, std::vector<zx::event>(), std::vector<zx::event>(), nullptr);
- image_pipe->PresentImage(imageIdB, 0, std::vector<zx::event>(), std::vector<zx::event>(), nullptr);
+ image_pipe->PresentImage(imageIdA, 0, std::vector<zx::event>(),
+ std::vector<zx::event>(), nullptr);
+ image_pipe->PresentImage(imageIdB, 0, std::vector<zx::event>(),
+ std::vector<zx::event>(), nullptr);
RunLoopUntilIdle();
@@ -384,9 +386,11 @@
// In this case, we need to run to idle after presenting image A, so that
// image B is returned by the pool, marked dirty, and is free to be acquired
// again.
- image_pipe->PresentImage(imageIdA, 0, std::vector<zx::event>(), std::vector<zx::event>(), nullptr);
+ image_pipe->PresentImage(imageIdA, 0, std::vector<zx::event>(),
+ std::vector<zx::event>(), nullptr);
RunLoopUntilIdle();
- image_pipe->PresentImage(imageIdB, 0, std::vector<zx::event>(), std::vector<zx::event>(), nullptr);
+ image_pipe->PresentImage(imageIdB, 0, std::vector<zx::event>(),
+ std::vector<zx::event>(), nullptr);
RunLoopUntilIdle();
image_out = image_pipe->GetEscherImage();
diff --git a/lib/ui/gfx/tests/import_unittest.cc b/lib/ui/gfx/tests/import_unittest.cc
index 0244ec1..3ceab15 100644
--- a/lib/ui/gfx/tests/import_unittest.cc
+++ b/lib/ui/gfx/tests/import_unittest.cc
@@ -18,14 +18,14 @@
public:
ImportTest() {}
- fxl::RefPtr<SessionForTest> CreateSession() override {
+ std::unique_ptr<SessionForTest> CreateSession() override {
SessionContext session_context = CreateBarebonesSessionContext();
resource_linker_ = std::make_unique<ResourceLinker>();
session_context.resource_linker = resource_linker_.get();
- return fxl::MakeRefCounted<SessionForTest>(1, std::move(session_context),
- this, error_reporter());
+ return std::make_unique<SessionForTest>(1, std::move(session_context), this,
+ error_reporter());
}
std::unique_ptr<ResourceLinker> resource_linker_;
diff --git a/lib/ui/gfx/tests/mocks.cc b/lib/ui/gfx/tests/mocks.cc
index 0ef6d86..c013d2f 100644
--- a/lib/ui/gfx/tests/mocks.cc
+++ b/lib/ui/gfx/tests/mocks.cc
@@ -4,6 +4,7 @@
#include "garnet/lib/ui/gfx/tests/mocks.h"
+#include "garnet/lib/ui/gfx/tests/session_test.h"
#include "garnet/lib/ui/scenic/command_dispatcher.h"
namespace scenic_impl {
@@ -15,17 +16,15 @@
ErrorReporter* error_reporter)
: Session(id, std::move(context), event_reporter, error_reporter) {}
-void SessionForTest::TearDown() { Session::TearDown(); }
-
-SessionHandlerForTest::SessionHandlerForTest(CommandDispatcherContext context,
- SessionManager* session_manager,
+SessionHandlerForTest::SessionHandlerForTest(SessionManager* session_manager,
SessionContext session_context,
SessionId session_id,
+ Scenic* scenic,
EventReporter* event_reporter,
ErrorReporter* error_reporter)
- : SessionHandler(std::move(context), session_manager,
- std::move(session_context), session_id, event_reporter,
- error_reporter),
+ : SessionHandler(CommandDispatcherContext(scenic, nullptr, session_id),
+ session_manager, std::move(session_context), session_id,
+ event_reporter, error_reporter),
command_count_(0),
present_count_(0) {}
@@ -56,12 +55,9 @@
SessionManagerForTest::SessionManagerForTest() : SessionManager() {}
-std::unique_ptr<SessionHandler> SessionManagerForTest::CreateSessionHandler(
- CommandDispatcherContext context, Engine* engine, SessionId session_id,
- EventReporter* event_reporter, ErrorReporter* error_reporter) const {
- return std::make_unique<SessionHandlerForTest>(
- std::move(context), engine->session_manager(), engine->session_context(),
- session_id, event_reporter, error_reporter);
+void SessionManagerForTest::InsertSessionHandler(
+ SessionId session_id, SessionHandler* session_handler) {
+ SessionManager::InsertSessionHandler(session_id, session_handler);
}
EngineForTest::EngineForTest(DisplayManager* display_manager,
diff --git a/lib/ui/gfx/tests/mocks.h b/lib/ui/gfx/tests/mocks.h
index 9739152..578c69d 100644
--- a/lib/ui/gfx/tests/mocks.h
+++ b/lib/ui/gfx/tests/mocks.h
@@ -9,6 +9,7 @@
#include "garnet/lib/ui/gfx/engine/engine.h"
#include "garnet/lib/ui/gfx/engine/session.h"
#include "garnet/lib/ui/gfx/engine/session_handler.h"
+#include "garnet/lib/ui/scenic/scenic.h"
#include "lib/escher/flib/release_fence_signaller.h"
namespace scenic_impl {
@@ -20,15 +21,13 @@
SessionForTest(SessionId id, SessionContext context,
EventReporter* event_reporter = EventReporter::Default(),
ErrorReporter* error_reporter = ErrorReporter::Default());
-
- virtual void TearDown() override;
};
class SessionHandlerForTest : public SessionHandler {
public:
SessionHandlerForTest(
- CommandDispatcherContext context, SessionManager* session_manager,
- SessionContext session_context, SessionId session_id,
+ SessionManager* session_manager, SessionContext session_context,
+ SessionId session_id, Scenic* scenic,
EventReporter* event_reporter = EventReporter::Default(),
ErrorReporter* error_reporter = ErrorReporter::Default());
@@ -70,12 +69,8 @@
class SessionManagerForTest : public SessionManager {
public:
SessionManagerForTest();
-
- private:
- std::unique_ptr<SessionHandler> CreateSessionHandler(
- CommandDispatcherContext context, Engine* engine, SessionId session_id,
- EventReporter* event_reporter,
- ErrorReporter* error_reporter) const override;
+ void InsertSessionHandler(SessionId session_id,
+ SessionHandler* session_handler);
};
class EngineForTest : public Engine {
diff --git a/lib/ui/gfx/tests/resource_linker_unittest.cc b/lib/ui/gfx/tests/resource_linker_unittest.cc
index 71ec51d..1d57f64 100644
--- a/lib/ui/gfx/tests/resource_linker_unittest.cc
+++ b/lib/ui/gfx/tests/resource_linker_unittest.cc
@@ -21,14 +21,14 @@
public:
ResourceLinkerTest() {}
- fxl::RefPtr<SessionForTest> CreateSession() override {
+ std::unique_ptr<SessionForTest> CreateSession() override {
SessionContext session_context = CreateBarebonesSessionContext();
resource_linker_ = std::make_unique<ResourceLinker>();
session_context.resource_linker = resource_linker_.get();
- return fxl::MakeRefCounted<SessionForTest>(1, std::move(session_context),
- this, error_reporter());
+ return std::make_unique<SessionForTest>(1, std::move(session_context), this,
+ error_reporter());
}
std::unique_ptr<ResourceLinker> resource_linker_;
diff --git a/lib/ui/gfx/tests/session_handler_test.cc b/lib/ui/gfx/tests/session_handler_test.cc
new file mode 100644
index 0000000..5ac5b68
--- /dev/null
+++ b/lib/ui/gfx/tests/session_handler_test.cc
@@ -0,0 +1,42 @@
+// Copyright 2019 The Fuchsia 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 "garnet/lib/ui/gfx/tests/session_handler_test.h"
+
+namespace scenic_impl {
+namespace gfx {
+namespace test {
+
+void SessionHandlerTest::SetUp() { SessionTest::SetUp(); }
+
+void SessionHandlerTest::TearDown() {
+ SessionTest::TearDown();
+ session_handler_.reset();
+ scenic_.reset();
+ app_context_.reset();
+}
+
+void SessionHandlerTest::InitializeScenic() {
+ // TODO(SCN-720): Wrap CreateFromStartupInfo using ::gtest::Environment
+ // instead of this hack. This code has the chance to break non-ScenicTests.
+ app_context_ = component::StartupContext::CreateFromStartupInfo();
+ scenic_ = std::make_unique<Scenic>(app_context_.get(), [] {});
+}
+
+void SessionHandlerTest::InitializeSessionHandler() {
+ if (!scenic_) {
+ InitializeScenic();
+ }
+
+ auto session_context = CreateBarebonesSessionContext();
+ session_handler_ = std::make_unique<SessionHandlerForTest>(
+ session_manager_.get(), std::move(session_context), session_->id(),
+ scenic_.get());
+ session_manager_->InsertSessionHandler(session_->id(),
+ session_handler_.get());
+}
+
+} // namespace test
+} // namespace gfx
+} // namespace scenic_impl
diff --git a/lib/ui/gfx/tests/session_handler_test.h b/lib/ui/gfx/tests/session_handler_test.h
new file mode 100644
index 0000000..be07096
--- /dev/null
+++ b/lib/ui/gfx/tests/session_handler_test.h
@@ -0,0 +1,45 @@
+// Copyright 2019 The Fuchsia 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 GARNET_LIB_UI_GFX_TESTS_SESSION_HANDLER_TEST_H_
+#define GARNET_LIB_UI_GFX_TESTS_SESSION_HANDLER_TEST_H_
+
+#include "garnet/lib/ui/gfx/tests/session_test.h"
+
+#include <lib/fit/function.h>
+
+#include "garnet/lib/ui/gfx/displays/display_manager.h"
+#include "garnet/lib/ui/gfx/engine/engine.h"
+#include "garnet/lib/ui/gfx/engine/session.h"
+#include "garnet/lib/ui/gfx/tests/mocks.h"
+#include "garnet/lib/ui/scenic/event_reporter.h"
+#include "garnet/lib/ui/scenic/tests/scenic_test.h"
+#include "lib/gtest/test_loop_fixture.h"
+
+namespace scenic_impl {
+namespace gfx {
+namespace test {
+
+// For testing SessionHandler without having to manually provide all the state
+// necessary for SessionHandler to run
+class SessionHandlerTest : public SessionTest {
+ public:
+ void ResetSessionHandler() { session_handler_.reset(); }
+ void InitializeScenic();
+ void InitializeSessionHandler();
+
+ void SetUp() override;
+ void TearDown() override;
+
+ protected:
+ std::unique_ptr<component::StartupContext> app_context_;
+ std::unique_ptr<Scenic> scenic_;
+ std::unique_ptr<SessionHandlerForTest> session_handler_;
+};
+
+} // namespace test
+} // namespace gfx
+} // namespace scenic_impl
+
+#endif // GARNET_LIB_UI_GFX_TESTS_SESSION_HANDLER_TEST_H_
diff --git a/lib/ui/gfx/tests/session_handler_unittest.cc b/lib/ui/gfx/tests/session_handler_unittest.cc
new file mode 100644
index 0000000..3ba37e7
--- /dev/null
+++ b/lib/ui/gfx/tests/session_handler_unittest.cc
@@ -0,0 +1,30 @@
+// Copyright 2019 The Fuchsia 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 "garnet/lib/ui/gfx/tests/session_handler_test.h"
+
+#include "gtest/gtest.h"
+
+namespace scenic_impl {
+namespace gfx {
+namespace test {
+
+TEST_F(
+ SessionHandlerTest,
+ WhenSessionHandlerDestroyed_ShouldRemoveSessionHandlerPtrFromSessionManager) {
+ InitializeSessionHandler();
+ auto id = session_->id();
+
+ EXPECT_NE(session_handler_.get(), nullptr);
+ EXPECT_EQ(session_manager_->FindSessionHandler(id), session_handler_.get());
+
+ ResetSessionHandler();
+
+ EXPECT_EQ(session_handler_.get(), nullptr);
+ EXPECT_EQ(session_manager_->FindSessionHandler(id), nullptr);
+}
+
+} // namespace test
+} // namespace gfx
+} // namespace scenic_impl
diff --git a/lib/ui/gfx/tests/session_test.cc b/lib/ui/gfx/tests/session_test.cc
index 185008d..a902842 100644
--- a/lib/ui/gfx/tests/session_test.cc
+++ b/lib/ui/gfx/tests/session_test.cc
@@ -6,6 +6,8 @@
#include "garnet/lib/ui/gfx/tests/mocks.h"
+#include "lib/fxl/logging.h"
+
namespace scenic_impl {
namespace gfx {
namespace test {
@@ -22,13 +24,15 @@
void SessionTest::SetUp() { session_ = CreateSession(); }
void SessionTest::TearDown() {
- session_->TearDown();
- session_ = nullptr;
+ session_manager_.reset();
+ if (session_) {
+ session_.reset();
+ }
events_.clear();
}
SessionContext SessionTest::CreateBarebonesSessionContext() {
- session_manager_ = std::make_unique<SessionManager>();
+ session_manager_ = std::make_unique<SessionManagerForTest>();
update_scheduler_ =
std::make_unique<FakeUpdateScheduler>(session_manager_.get());
SessionContext session_context{
@@ -52,9 +56,9 @@
return session_context;
}
-fxl::RefPtr<SessionForTest> SessionTest::CreateSession() {
- return fxl::MakeRefCounted<SessionForTest>(1, CreateBarebonesSessionContext(),
- this, error_reporter());
+std::unique_ptr<SessionForTest> SessionTest::CreateSession() {
+ return std::make_unique<SessionForTest>(1, CreateBarebonesSessionContext(),
+ this, error_reporter());
}
void SessionTest::EnqueueEvent(fuchsia::ui::gfx::Event event) {
diff --git a/lib/ui/gfx/tests/session_test.h b/lib/ui/gfx/tests/session_test.h
index 7cdccb7..3916eaf 100644
--- a/lib/ui/gfx/tests/session_test.h
+++ b/lib/ui/gfx/tests/session_test.h
@@ -9,11 +9,11 @@
#include <lib/fit/function.h>
-#include "garnet/lib/ui/gfx/displays/display_manager.h"
#include "garnet/lib/ui/gfx/engine/engine.h"
#include "garnet/lib/ui/gfx/engine/session.h"
#include "garnet/lib/ui/gfx/tests/mocks.h"
#include "garnet/lib/ui/scenic/event_reporter.h"
+#include "garnet/lib/ui/scenic/tests/scenic_test.h"
#include "lib/gtest/test_loop_fixture.h"
namespace scenic_impl {
@@ -42,7 +42,7 @@
void EnqueueEvent(fuchsia::ui::scenic::Command unhandled) override;
// Subclasses should override to provide their own Session.
- virtual fxl::RefPtr<SessionForTest> CreateSession();
+ virtual std::unique_ptr<SessionForTest> CreateSession();
// Creates a SessionContext with only a SessionManager and a
// FakeUpdateScheduler.
@@ -60,9 +60,9 @@
return session_->resources()->FindResource<ResourceT>(id);
}
- std::unique_ptr<SessionManager> session_manager_;
std::unique_ptr<UpdateScheduler> update_scheduler_;
- fxl::RefPtr<SessionForTest> session_;
+ std::unique_ptr<SessionForTest> session_;
+ std::unique_ptr<SessionManagerForTest> session_manager_;
std::vector<fuchsia::ui::scenic::Event> events_;
};
diff --git a/lib/ui/gfx/tests/session_unittest.cc b/lib/ui/gfx/tests/session_unittest.cc
index 5041b47..22b823b 100644
--- a/lib/ui/gfx/tests/session_unittest.cc
+++ b/lib/ui/gfx/tests/session_unittest.cc
@@ -19,14 +19,12 @@
namespace test {
TEST_F(SessionTest, ScheduleUpdateOutOfOrder) {
- EXPECT_TRUE(
- session_->ScheduleUpdate(1, std::vector<::fuchsia::ui::gfx::Command>(),
- ::std::vector<zx::event>(),
- ::std::vector<zx::event>(), [](auto) {}));
- EXPECT_FALSE(
- session_->ScheduleUpdate(0, std::vector<::fuchsia::ui::gfx::Command>(),
- ::std::vector<zx::event>(),
- ::std::vector<zx::event>(), [](auto) {}));
+ EXPECT_TRUE(session_->ScheduleUpdate(
+ /*presentation_time*/ 1, std::vector<::fuchsia::ui::gfx::Command>(),
+ std::vector<zx::event>(), std::vector<zx::event>(), [](auto) {}));
+ EXPECT_FALSE(session_->ScheduleUpdate(
+ /*presentation_time*/ 0, std::vector<::fuchsia::ui::gfx::Command>(),
+ std::vector<zx::event>(), std::vector<zx::event>(), [](auto) {}));
ExpectLastReportedError(
"scenic_impl::gfx::Session: Present called with out-of-order "
"presentation "
@@ -35,14 +33,12 @@
}
TEST_F(SessionTest, ScheduleUpdateInOrder) {
- EXPECT_TRUE(
- session_->ScheduleUpdate(1, std::vector<::fuchsia::ui::gfx::Command>(),
- ::std::vector<zx::event>(),
- ::std::vector<zx::event>(), [](auto) {}));
- EXPECT_TRUE(
- session_->ScheduleUpdate(1, std::vector<::fuchsia::ui::gfx::Command>(),
- ::std::vector<zx::event>(),
- ::std::vector<zx::event>(), [](auto) {}));
+ EXPECT_TRUE(session_->ScheduleUpdate(
+ /*presentation_time*/ 1, std::vector<::fuchsia::ui::gfx::Command>(),
+ std::vector<zx::event>(), std::vector<zx::event>(), [](auto) {}));
+ EXPECT_TRUE(session_->ScheduleUpdate(
+ /*presentation_time*/ 1, std::vector<::fuchsia::ui::gfx::Command>(),
+ std::vector<zx::event>(), std::vector<zx::event>(), [](auto) {}));
ExpectLastReportedError(nullptr);
}
@@ -96,14 +92,14 @@
EXPECT_TRUE(Apply(scenic::NewSetLabelCmd(kNodeId, kLongLabel)));
EXPECT_EQ(kLongLabel, shape_node->label());
EXPECT_TRUE(Apply(scenic::NewSetLabelCmd(kNodeId, kTooLongLabel)));
- EXPECT_EQ(kTooLongLabel.substr(0, ::fuchsia::ui::gfx::kLabelMaxLength),
+ EXPECT_EQ(kTooLongLabel.substr(0, fuchsia::ui::gfx::kLabelMaxLength),
shape_node->label());
EXPECT_TRUE(Apply(scenic::NewSetLabelCmd(kNodeId, "")));
EXPECT_TRUE(shape_node->label().empty());
// Bypass the truncation performed by session helpers.
shape_node->SetLabel(kTooLongLabel);
- EXPECT_EQ(kTooLongLabel.substr(0, ::fuchsia::ui::gfx::kLabelMaxLength),
+ EXPECT_EQ(kTooLongLabel.substr(0, fuchsia::ui::gfx::kLabelMaxLength),
shape_node->label());
}
diff --git a/lib/ui/gfx/tests/size_change_hint_unittest.cc b/lib/ui/gfx/tests/size_change_hint_unittest.cc
index b5377a3..c5698d4 100644
--- a/lib/ui/gfx/tests/size_change_hint_unittest.cc
+++ b/lib/ui/gfx/tests/size_change_hint_unittest.cc
@@ -15,14 +15,14 @@
public:
SizeChangeHintTest() {}
- fxl::RefPtr<SessionForTest> CreateSession() override {
+ std::unique_ptr<SessionForTest> CreateSession() override {
SessionContext session_context = CreateBarebonesSessionContext();
resource_linker_ = std::make_unique<ResourceLinker>();
session_context.resource_linker = resource_linker_.get();
- return fxl::MakeRefCounted<SessionForTest>(1, std::move(session_context),
- this, error_reporter());
+ return std::make_unique<SessionForTest>(1, std::move(session_context), this,
+ error_reporter());
}
std::unique_ptr<ResourceLinker> resource_linker_;
diff --git a/lib/ui/gfx/tests/view_unittest.cc b/lib/ui/gfx/tests/view_unittest.cc
index 48b72c6..67f9420 100644
--- a/lib/ui/gfx/tests/view_unittest.cc
+++ b/lib/ui/gfx/tests/view_unittest.cc
@@ -23,14 +23,14 @@
public:
ViewTest() {}
- fxl::RefPtr<SessionForTest> CreateSession() override {
+ std::unique_ptr<SessionForTest> CreateSession() override {
SessionContext session_context = CreateBarebonesSessionContext();
view_linker_ = std::make_unique<ViewLinker>();
session_context.view_linker = view_linker_.get();
- return fxl::MakeRefCounted<SessionForTest>(1, std::move(session_context),
- this, error_reporter());
+ return std::make_unique<SessionForTest>(1, std::move(session_context), this,
+ error_reporter());
}
std::unique_ptr<ViewLinker> view_linker_;
diff --git a/lib/ui/gfx/tests/vk_session_test.cc b/lib/ui/gfx/tests/vk_session_test.cc
index 66aeec9..c5db90d 100644
--- a/lib/ui/gfx/tests/vk_session_test.cc
+++ b/lib/ui/gfx/tests/vk_session_test.cc
@@ -9,7 +9,7 @@
namespace gfx {
namespace test {
-fxl::RefPtr<SessionForTest> VkSessionTest::CreateSession() {
+std::unique_ptr<SessionForTest> VkSessionTest::CreateSession() {
SessionContext session_context = CreateBarebonesSessionContext();
// Initialize Vulkan.
@@ -37,8 +37,8 @@
session_context.escher_image_factory = image_factory_.get();
session_context.release_fence_signaller = release_fence_signaller_.get();
- return fxl::MakeRefCounted<SessionForTest>(1, std::move(session_context),
- this, error_reporter());
+ return std::make_unique<SessionForTest>(1, std::move(session_context), this,
+ error_reporter());
}
} // namespace test
diff --git a/lib/ui/gfx/tests/vk_session_test.h b/lib/ui/gfx/tests/vk_session_test.h
index d1b1649..7eb8b7d 100644
--- a/lib/ui/gfx/tests/vk_session_test.h
+++ b/lib/ui/gfx/tests/vk_session_test.h
@@ -14,7 +14,7 @@
class VkSessionTest : public SessionTest {
public:
// |SessionTest|
- fxl::RefPtr<SessionForTest> CreateSession() override;
+ std::unique_ptr<SessionForTest> CreateSession() override;
private:
std::unique_ptr<escher::Escher> escher_;
diff --git a/lib/ui/scenic/command_dispatcher.cc b/lib/ui/scenic/command_dispatcher.cc
index d92a6f8..d3ec99c 100644
--- a/lib/ui/scenic/command_dispatcher.cc
+++ b/lib/ui/scenic/command_dispatcher.cc
@@ -4,21 +4,28 @@
#include "garnet/lib/ui/scenic/command_dispatcher.h"
+#include "garnet/lib/ui/scenic/scenic.h"
#include "garnet/lib/ui/scenic/session.h"
namespace scenic_impl {
CommandDispatcherContext::CommandDispatcherContext(Scenic* scenic,
Session* session)
- : scenic_(scenic), session_(session), session_id_(session->id()) {
- FXL_DCHECK(scenic_);
- FXL_DCHECK(session_);
- FXL_DCHECK(session_id_);
+ : CommandDispatcherContext(scenic, session, session->id()) {}
+
+CommandDispatcherContext::CommandDispatcherContext(Scenic* scenic,
+ Session* session,
+ SessionId id)
+ : scenic_(scenic), session_(session), session_id_(id) {
+ if (session) {
+ FXL_DCHECK(session->id() == id);
+ }
}
CommandDispatcherContext::CommandDispatcherContext(
CommandDispatcherContext&& context)
- : CommandDispatcherContext(context.scenic_, context.session_) {
+ : CommandDispatcherContext(context.scenic_, context.session_,
+ context.session_id_) {
auto& other_scenic = const_cast<Scenic*&>(context.scenic_);
auto& other_session = const_cast<Session*&>(context.session_);
auto& other_session_id = const_cast<SessionId&>(context.session_id_);
@@ -27,6 +34,10 @@
other_session_id = 0;
}
+void CommandDispatcherContext::KillSession() {
+ scenic_->CloseSession(session());
+}
+
CommandDispatcher::CommandDispatcher(CommandDispatcherContext context)
: context_(std::move(context)) {}
diff --git a/lib/ui/scenic/command_dispatcher.h b/lib/ui/scenic/command_dispatcher.h
index 62a1de6..daffeb9 100644
--- a/lib/ui/scenic/command_dispatcher.h
+++ b/lib/ui/scenic/command_dispatcher.h
@@ -15,15 +15,26 @@
// Provides the capabilities that a CommandDispatcher needs to do its job,
// without directly exposing the Session.
-class CommandDispatcherContext final {
+class CommandDispatcherContext {
public:
explicit CommandDispatcherContext(Scenic* scenic, Session* session);
+
+ explicit CommandDispatcherContext(Scenic* scenic, Session* session,
+ SessionId id);
+
CommandDispatcherContext(CommandDispatcherContext&& context);
// TODO(SCN-808): can/should we avoid exposing any/all of these?
- Scenic* scenic() { return scenic_; }
- Session* session() { return session_; }
- SessionId session_id() { return session_id_; }
+ Session* session() {
+ FXL_DCHECK(session_);
+ return session_;
+ }
+ SessionId session_id() {
+ FXL_DCHECK(session_id_);
+ return session_id_;
+ }
+
+ void KillSession();
private:
Scenic* const scenic_;
diff --git a/lib/ui/scenic/scenic.cc b/lib/ui/scenic/scenic.cc
index 5036333..d5dd0f6 100644
--- a/lib/ui/scenic/scenic.cc
+++ b/lib/ui/scenic/scenic.cc
@@ -38,11 +38,15 @@
}
void Scenic::CloseSession(Session* session) {
+ // TODO(SCN-1065): Make it so that close session removes the binding from
+ // session_bindings_, then remove num_sessions_ and return
+ // session_bindings_.size() in num_sessions() instead
for (auto& binding : session_bindings_.bindings()) {
// It's possible that this is called by BindingSet::CloseAndCheckForEmpty.
// In that case, binding could be empty, so check for that.
if (binding && binding->impl().get() == session) {
binding->Unbind();
+ --num_sessions_;
return;
}
}
@@ -67,7 +71,7 @@
::fidl::InterfaceRequest<fuchsia::ui::scenic::Session> session_request,
::fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener) {
auto session =
- std::make_unique<Session>(this, next_session_id_++, std::move(listener));
+ std::make_unique<Session>(next_session_id_++, std::move(listener));
// Give each installed System an opportunity to install a CommandDispatcher in
// the newly-created Session.
@@ -82,6 +86,7 @@
session->SetCommandDispatchers(std::move(dispatchers));
session_bindings_.AddBinding(std::move(session), std::move(session_request));
+ ++num_sessions_;
}
void Scenic::GetDisplayInfo(
diff --git a/lib/ui/scenic/scenic.h b/lib/ui/scenic/scenic.h
index 85521c5..4b28276 100644
--- a/lib/ui/scenic/scenic.h
+++ b/lib/ui/scenic/scenic.h
@@ -43,7 +43,7 @@
component::StartupContext* app_context() const { return app_context_; }
- size_t num_sessions() { return session_bindings_.size(); }
+ size_t num_sessions() { return num_sessions_; }
private:
void CreateSessionImmediately(
@@ -83,6 +83,7 @@
fidl::BindingSet<fuchsia::ui::scenic::Scenic> scenic_bindings_;
size_t next_session_id_ = 1;
+ size_t num_sessions_ = 0;
FXL_DISALLOW_COPY_AND_ASSIGN(Scenic);
};
diff --git a/lib/ui/scenic/session.cc b/lib/ui/scenic/session.cc
index fb2caf9..c39e344 100644
--- a/lib/ui/scenic/session.cc
+++ b/lib/ui/scenic/session.cc
@@ -10,11 +10,9 @@
namespace scenic_impl {
Session::Session(
- Scenic* owner, SessionId id,
+ SessionId id,
::fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener)
- : scenic_(owner), id_(id), listener_(listener.Bind()), weak_factory_(this) {
- FXL_DCHECK(scenic_);
-}
+ : id_(id), listener_(listener.Bind()), weak_factory_(this) {}
Session::~Session() = default;
diff --git a/lib/ui/scenic/session.h b/lib/ui/scenic/session.h
index c8599f9..c3ff924 100644
--- a/lib/ui/scenic/session.h
+++ b/lib/ui/scenic/session.h
@@ -32,7 +32,7 @@
public ErrorReporter {
public:
Session(
- Scenic* owner, SessionId id,
+ SessionId id,
::fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener);
~Session() override;
@@ -102,7 +102,6 @@
// invoke the callback for each event.
void FlushEvents();
- Scenic* const scenic_;
const SessionId id_;
::fidl::InterfacePtr<fuchsia::ui::scenic::SessionListener> listener_;
diff --git a/lib/ui/scenic/tests/BUILD.gn b/lib/ui/scenic/tests/BUILD.gn
index 5faf04c..dd69baa 100644
--- a/lib/ui/scenic/tests/BUILD.gn
+++ b/lib/ui/scenic/tests/BUILD.gn
@@ -13,30 +13,23 @@
source_set("testing_deps") {
testonly = true
sources = [
+ "scenic_gfx_test.cc",
+ "scenic_gfx_test.h",
"scenic_test.cc",
"scenic_test.h",
]
public_deps = [
+ ":mocks",
+ "//garnet/lib/ui/gfx",
"//garnet/lib/ui/scenic",
"//garnet/public/lib/component/cpp",
"//garnet/public/lib/fxl",
"//garnet/public/lib/gtest",
+ "//garnet/public/lib/ui/scenic/cpp",
"//third_party/googletest:gtest_main",
]
}
-executable("unittests") {
- output_name = "scenic_unittests"
- testonly = true
- sources = [
- "scenic_unittest.cc",
- ]
- deps = [
- ":dummy_system",
- ":testing_deps",
- ]
-}
-
source_set("dummy_system") {
sources = [
"dummy_system.cc",
@@ -47,3 +40,27 @@
"//garnet/public/fidl/fuchsia.ui.scenic",
]
}
+
+source_set("mocks") {
+ sources = [
+ "mocks.cc",
+ "mocks.h",
+ ]
+ deps = [
+ ":dummy_system",
+ "//garnet/lib/ui/gfx",
+ ]
+}
+
+executable("unittests") {
+ output_name = "scenic_unittests"
+ testonly = true
+ sources = [
+ "scenic_unittest.cc",
+ ]
+ deps = [
+ ":dummy_system",
+ ":mocks",
+ ":testing_deps",
+ ]
+}
diff --git a/lib/ui/scenic/tests/mocks.cc b/lib/ui/scenic/tests/mocks.cc
new file mode 100644
index 0000000..047cac6
--- /dev/null
+++ b/lib/ui/scenic/tests/mocks.cc
@@ -0,0 +1,28 @@
+// Copyright 2019 The Fuchsia 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 "garnet/lib/ui/scenic/tests/mocks.h"
+
+namespace scenic_impl {
+namespace test {
+
+ReleaseFenceSignallerForTest::ReleaseFenceSignallerForTest(
+ escher::impl::CommandBufferSequencer* command_buffer_sequencer)
+ : ReleaseFenceSignaller(command_buffer_sequencer) {}
+
+void ReleaseFenceSignallerForTest::AddCPUReleaseFence(zx::event fence) {
+ ++num_calls_to_add_cpu_release_fence_;
+ // Signal immediately for testing purposes.
+ fence.signal(0u, escher::kFenceSignalled);
+}
+
+EngineForTest::EngineForTest(
+ gfx::DisplayManager* display_manager,
+ std::unique_ptr<escher::ReleaseFenceSignaller> release_signaler,
+ escher::EscherWeakPtr escher)
+ : gfx::Engine(display_manager, std::move(release_signaler),
+ std::make_unique<gfx::SessionManager>(), std::move(escher)) {}
+
+} // namespace test
+} // namespace scenic_impl
diff --git a/lib/ui/scenic/tests/mocks.h b/lib/ui/scenic/tests/mocks.h
new file mode 100644
index 0000000..3dd58ea
--- /dev/null
+++ b/lib/ui/scenic/tests/mocks.h
@@ -0,0 +1,86 @@
+// Copyright 2019 The Fuchsia 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 GARNET_LIB_UI_SCENIC_TESTS_MOCKS_H_
+#define GARNET_LIB_UI_SCENIC_TESTS_MOCKS_H_
+
+#include "garnet/lib/ui/gfx/gfx_system.h"
+#include "garnet/lib/ui/scenic/tests/dummy_system.h"
+#include "lib/escher/flib/release_fence_signaller.h"
+
+namespace scenic_impl {
+namespace test {
+
+class ReleaseFenceSignallerForTest : public escher::ReleaseFenceSignaller {
+ public:
+ ReleaseFenceSignallerForTest(
+ escher::impl::CommandBufferSequencer* command_buffer_sequencer);
+
+ void AddCPUReleaseFence(zx::event fence) override;
+
+ uint32_t num_calls_to_add_cpu_release_fence() {
+ return num_calls_to_add_cpu_release_fence_;
+ }
+
+ private:
+ uint32_t num_calls_to_add_cpu_release_fence_ = 0;
+};
+
+class EngineForTest : public gfx::Engine {
+ public:
+ EngineForTest(gfx::DisplayManager* display_manager,
+ std::unique_ptr<escher::ReleaseFenceSignaller> release_signaler,
+ escher::EscherWeakPtr escher = escher::EscherWeakPtr());
+};
+
+class GfxSystemForTest : public gfx::GfxSystem {
+ public:
+ static constexpr TypeId kTypeId = kGfx;
+
+ explicit GfxSystemForTest(
+ SystemContext context,
+ std::unique_ptr<gfx::DisplayManager> display_manager,
+ escher::impl::CommandBufferSequencer* command_buffer_sequencer)
+ : GfxSystem(std::move(context), std::move(display_manager)),
+ command_buffer_sequencer_(command_buffer_sequencer) {}
+
+ gfx::Engine* engine() { return engine_.get(); }
+
+ private:
+ std::unique_ptr<gfx::Engine> InitializeEngine() override {
+ return std::make_unique<EngineForTest>(
+ display_manager_.get(), std::make_unique<ReleaseFenceSignallerForTest>(
+ command_buffer_sequencer_));
+ }
+
+ std::unique_ptr<escher::Escher> InitializeEscher() override {
+ return nullptr;
+ }
+
+ escher::impl::CommandBufferSequencer* command_buffer_sequencer_;
+};
+
+// Device-independent "display"; for testing only. Needed to ensure GfxSystem
+// doesn't wait for a device-driven "display ready" signal.
+class TestDisplay : public scenic_impl::gfx::Display {
+ public:
+ TestDisplay(uint64_t id, uint32_t width_px, uint32_t height_px)
+ : Display(id, width_px, height_px) {}
+ ~TestDisplay() = default;
+ bool is_test_display() const override { return true; }
+};
+
+class MockSystemWithDelayedInitialization : public DummySystem {
+ public:
+ // Expose to tests.
+ using System::SetToInitialized;
+
+ explicit MockSystemWithDelayedInitialization(SystemContext context)
+ : DummySystem(std::move(context), false) {}
+};
+
+} // namespace test
+} // namespace scenic_impl
+
+#endif // GARNET_LIB_UI_SCENIC_TESTS_MOCKS_H_
diff --git a/lib/ui/scenic/tests/scenic_gfx_test.cc b/lib/ui/scenic/tests/scenic_gfx_test.cc
new file mode 100644
index 0000000..31e141a
--- /dev/null
+++ b/lib/ui/scenic/tests/scenic_gfx_test.cc
@@ -0,0 +1,34 @@
+// Copyright 2019 The Fuchsia 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 "garnet/lib/ui/scenic/tests/scenic_gfx_test.h"
+
+#include "garnet/lib/ui/gfx/displays/display.h"
+#include "garnet/lib/ui/gfx/displays/display_manager.h"
+#include "garnet/lib/ui/scenic/tests/mocks.h"
+#include <lib/async-testutils/test_loop.h>
+
+namespace scenic_impl {
+namespace test {
+
+void ScenicGfxTest::InitializeScenic(Scenic* scenic) {
+ auto display_manager = std::make_unique<gfx::DisplayManager>();
+ display_manager->SetDefaultDisplayForTests(
+ std::make_unique<test::TestDisplay>(
+ /*id*/ 0, /* width */ 0, /* height */ 0));
+ command_buffer_sequencer_ =
+ std::make_unique<escher::impl::CommandBufferSequencer>();
+ scenic_->RegisterSystem<GfxSystemForTest>(std::move(display_manager),
+ command_buffer_sequencer_.get());
+
+ RunLoopUntilIdle(); // Finish initialization
+}
+
+void ScenicGfxTest::TearDown() {
+ ScenicTest::TearDown();
+ command_buffer_sequencer_.reset();
+}
+
+} // namespace test
+} // namespace scenic_impl
diff --git a/lib/ui/scenic/tests/scenic_gfx_test.h b/lib/ui/scenic/tests/scenic_gfx_test.h
new file mode 100644
index 0000000..f94c6f9
--- /dev/null
+++ b/lib/ui/scenic/tests/scenic_gfx_test.h
@@ -0,0 +1,27 @@
+// Copyright 2019 The Fuchsia 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 GARNET_LIB_UI_SCENIC_TESTS_SCENIC_GFX_TEST_H_
+#define GARNET_LIB_UI_SCENIC_TESTS_SCENIC_GFX_TEST_H_
+
+#include "garnet/lib/ui/scenic/tests/scenic_test.h"
+#include "garnet/public/lib/escher/impl/command_buffer_sequencer.h"
+
+namespace scenic_impl {
+namespace test {
+
+// Subclass of ScenicTest for tests requiring Scenic with a gfx system installed
+class ScenicGfxTest : public ScenicTest {
+ protected:
+ void TearDown() override;
+ void InitializeScenic(Scenic* scenic) override;
+
+ std::unique_ptr<escher::impl::CommandBufferSequencer>
+ command_buffer_sequencer_;
+};
+
+} // namespace test
+} // namespace scenic_impl
+
+#endif // GARNET_LIB_UI_SCENIC_TESTS_SCENIC_GFX_TEST_H_
diff --git a/lib/ui/scenic/tests/scenic_test.cc b/lib/ui/scenic/tests/scenic_test.cc
index 585edfd..2ce38e5 100644
--- a/lib/ui/scenic/tests/scenic_test.cc
+++ b/lib/ui/scenic/tests/scenic_test.cc
@@ -2,7 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "garnet/lib/ui/scenic/tests/scenic_test.h"
+#include "garnet/lib/ui/scenic/tests/scenic_gfx_test.h"
+
+#include "garnet/lib/ui/gfx/displays/display.h"
+#include "garnet/lib/ui/gfx/displays/display_manager.h"
+#include "garnet/lib/ui/scenic/tests/mocks.h"
namespace scenic_impl {
namespace test {
@@ -12,7 +16,7 @@
void ScenicTest::SetUp() {
// TODO(SCN-720): Wrap CreateFromStartupInfo using ::gtest::Environment
// instead of this hack. This code has the chance to break non-ScenicTests.
- if (app_context_ == nullptr) {
+ if (app_context_.get() == nullptr) {
app_context_ = component::StartupContext::CreateFromStartupInfo();
}
scenic_ =
@@ -24,10 +28,21 @@
reported_errors_.clear();
events_.clear();
scenic_.reset();
+ app_context_.reset();
}
void ScenicTest::InitializeScenic(Scenic* scenic) {}
+std::unique_ptr<::scenic::Session> ScenicTest::CreateSession() {
+ fuchsia::ui::scenic::SessionPtr session_ptr;
+ fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener_handle;
+ fidl::InterfaceRequest<fuchsia::ui::scenic::SessionListener>
+ listener_request = listener_handle.NewRequest();
+ scenic()->CreateSession(session_ptr.NewRequest(), std::move(listener_handle));
+ return std::make_unique<::scenic::Session>(std::move(session_ptr),
+ std::move(listener_request));
+}
+
void ScenicTest::ReportError(fxl::LogSeverity severity,
std::string error_string) {
// Typically, we don't want to log expected errors when running the tests.
diff --git a/lib/ui/scenic/tests/scenic_test.h b/lib/ui/scenic/tests/scenic_test.h
index 82eb15f..b2d692a 100644
--- a/lib/ui/scenic/tests/scenic_test.h
+++ b/lib/ui/scenic/tests/scenic_test.h
@@ -9,6 +9,7 @@
#include "garnet/lib/ui/scenic/scenic.h"
#include "garnet/lib/ui/scenic/util/error_reporter.h"
+#include "garnet/public/lib/ui/scenic/cpp/session.h"
#include "gtest/gtest.h"
#include "lib/component/cpp/startup_context.h"
#include "lib/fxl/tasks/task_runner.h"
@@ -22,6 +23,9 @@
class ScenicTest : public ::gtest::TestLoopFixture,
public ErrorReporter,
public EventReporter {
+ public:
+ std::unique_ptr<::scenic::Session> CreateSession();
+
protected:
// ::testing::Test virtual method.
void SetUp() override;
diff --git a/lib/ui/scenic/tests/scenic_unittest.cc b/lib/ui/scenic/tests/scenic_unittest.cc
index 329d06c..ff9743b 100644
--- a/lib/ui/scenic/tests/scenic_unittest.cc
+++ b/lib/ui/scenic/tests/scenic_unittest.cc
@@ -3,39 +3,47 @@
// found in the LICENSE file.
#include "garnet/lib/ui/scenic/tests/dummy_system.h"
+#include "garnet/lib/ui/scenic/tests/mocks.h"
+#include "garnet/lib/ui/scenic/tests/scenic_gfx_test.h"
#include "garnet/lib/ui/scenic/tests/scenic_test.h"
+#include "gtest/gtest.h"
+
namespace scenic_impl {
namespace test {
-namespace {
-
-class MockSystemWithDelayedInitialization : public DummySystem {
- public:
- // Expose to tests.
- using System::SetToInitialized;
-
- explicit MockSystemWithDelayedInitialization(SystemContext context)
- : DummySystem(std::move(context), false) {}
-};
-
-} // anonymous namespace
-
TEST_F(ScenicTest, SessionCreatedAfterAllSystemsInitialized) {
auto mock_system =
- scenic()->RegisterSystem<test::MockSystemWithDelayedInitialization>();
+ scenic()->RegisterSystem<MockSystemWithDelayedInitialization>();
- EXPECT_EQ(0U, scenic()->num_sessions());
+ EXPECT_EQ(scenic()->num_sessions(), 0U);
// Request session creation, which doesn't occur yet because system isn't
// initialized.
- fuchsia::ui::scenic::SessionPtr session;
- scenic()->CreateSession(session.NewRequest(), nullptr);
- EXPECT_EQ(0U, scenic()->num_sessions());
+ auto session = CreateSession();
+ EXPECT_EQ(scenic()->num_sessions(), 0U);
// Initializing the system allows the session to be created.
mock_system->SetToInitialized();
- EXPECT_EQ(1U, scenic()->num_sessions());
+ EXPECT_EQ(scenic()->num_sessions(), 1U);
+}
+
+TEST_F(ScenicGfxTest, InvalidPresentCall_ShouldDestroySession) {
+ EXPECT_EQ(scenic()->num_sessions(), 0U);
+ auto session = CreateSession();
+ EXPECT_EQ(scenic()->num_sessions(), 1U);
+
+ session->Present(/*Presentation Time*/ 10,
+ /*Present Callback*/ [](auto){});
+
+ // Trigger error by making a present call with an earlier presentation time
+ // than the previous call to present
+ session->Present(/*Presentation Time*/ 0,
+ /*Present Callback*/ [](auto){});
+
+ RunLoopUntilIdle();
+
+ EXPECT_EQ(scenic()->num_sessions(), 0U);
}
} // namespace test