blob: 5443176cf654ac52aa5a3b905dcef4617edd490a [file] [log] [blame]
// 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/cpp/task.h>
#include <lib/async/default.h>
#include <lib/fostr/fidl/fuchsia/ui/gfx/formatting.h>
#include <lib/zx/eventpair.h>
#include <trace/event.h>
#include "garnet/lib/ui/gfx/engine/hit_tester.h"
#include "garnet/lib/ui/gfx/engine/resource_linker.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/lights/point_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/screenshotter.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/validate_eventpair.h"
#include "garnet/lib/ui/gfx/util/wrap.h"
#include "src/ui/lib/escher/hmd/pose_buffer.h"
#include "src/ui/lib/escher/renderer/batch_gpu_uploader.h"
#include "src/ui/lib/escher/shape/mesh.h"
#include "src/ui/lib/escher/shape/rounded_rect_factory.h"
#include "src/ui/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
CommandContext::CommandContext(std::unique_ptr<escher::BatchGpuUploader> uploader)
: batch_gpu_uploader_(std::move(uploader)) {}
void CommandContext::Flush() {
if (batch_gpu_uploader_) {
// Submit regardless of whether or not there are updates to release the
// underlying CommandBuffer so the pool and sequencer don't stall out.
// TODO(ES-115) to remove this restriction.
batch_gpu_uploader_->Submit();
}
}
bool GfxCommandApplier::AssertValueIsOfType(const fuchsia::ui::gfx::Value& value,
const fuchsia::ui::gfx::Value::Tag* tags,
size_t tag_count, Session* session) {
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.debug", "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: {
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::kSetClipPlanes:
return ApplySetClipPlanesCmd(session, std::move(command.set_clip_planes()));
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::kSetPointLightPosition:
return ApplySetPointLightPositionCmd(session, std::move(command.set_point_light_position()));
case fuchsia::ui::gfx::Command::Tag::kSetPointLightFalloff:
return ApplySetPointLightFalloffCmd(session, std::move(command.set_point_light_falloff()));
case fuchsia::ui::gfx::Command::Tag::kAddLight:
return ApplyAddLightCmd(session, std::move(command.add_light()));
case fuchsia::ui::gfx::Command::Tag::kScene_AddAmbientLight:
return ApplySceneAddAmbientLightCmd(session, std::move(command.scene__add_ambient_light()));
case fuchsia::ui::gfx::Command::Tag::kScene_AddDirectionalLight:
return ApplySceneAddDirectionalLightCmd(session,
std::move(command.scene__add_directional_light()));
case fuchsia::ui::gfx::Command::Tag::kScene_AddPointLight:
return ApplySceneAddPointLightCmd(session, std::move(command.scene__add_point_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::kSetDisplayColorConversion:
return ApplySetDisplayColorConversionCmd(session,
std::move(command.set_display_color_conversion()));
case fuchsia::ui::gfx::Command::Tag::kSetDisplayRotation:
return ApplySetDisplayRotationCmd(session, std::move(command.set_display_rotation()));
case fuchsia::ui::gfx::Command::Tag::kSetEnableViewDebugBounds:
return ApplySetEnableViewDebugBounds(session,
std::move(command.set_enable_view_debug_bounds()));
case fuchsia::ui::gfx::Command::Tag::kSetViewHolderBoundsColor:
return ApplySetViewHolderBoundsColor(session,
std::move(command.set_view_holder_bounds_color()));
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) {
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::kPointLight:
return ApplyCreatePointLight(session, id, std::move(command.resource.point_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::kView2:
return ApplyCreateView(session, id,
fuchsia::ui::gfx::ViewArgs{
.token = std::move(command.resource.view2().token),
.debug_name = std::move(command.resource.view2().debug_name),
});
case fuchsia::ui::gfx::ResourceArgs::Tag::kViewHolder2:
return ApplyCreateViewHolder(
session, id,
fuchsia::ui::gfx::ViewHolderArgs{
.token = std::move(command.resource.view_holder2().token),
.debug_name = std::move(command.resource.view_holder2().debug_name),
});
case fuchsia::ui::gfx::ResourceArgs::Tag::kView3:
return ApplyCreateView(session, id, std::move(command.resource.view3()));
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' ViewNodes
// TODO(SCN-795): Split these out into separate commands? or just allow node
// to handle these??
auto child = session->resources()->FindResource<Node>(command.child_id);
if (!child) {
return false;
}
if (auto parent = session->resources()->FindResource<Node>(
command.node_id, ResourceMap::ErrorBehavior::kDontReportErrors)) {
return parent->AddChild(std::move(child), session->error_reporter());
} else if (auto view = session->resources()->FindResource<View>(
command.node_id, ResourceMap::ErrorBehavior::kDontReportErrors)) {
// Children are added to a View. Add them the corresponding ViewNode.
return view->GetViewNode()->AddChild(std::move(child), session->error_reporter());
}
session->error_reporter()->ERROR() << "No View or Node found with id " << command.node_id;
return false;
}
bool GfxCommandApplier::ApplyAddPartCmd(Session* session, fuchsia::ui::gfx::AddPartCmd command) {
// This is now a no-op.
FXL_LOG(INFO) << "AddPart is illegal now.";
session->error_reporter()->ERROR() << "AddPartCmd is now a no-op. Do not use.";
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(std::move(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::ApplySetDisplayColorConversionCmd(
Session* session, fuchsia::ui::gfx::SetDisplayColorConversionCmdHACK command) {
if (auto compositor = session->resources()->FindResource<Compositor>(command.compositor_id)) {
if (auto swapchain = compositor->swapchain()) {
ColorTransform transform;
transform.preoffsets = command.preoffsets;
transform.matrix = command.matrix;
transform.postoffsets = command.postoffsets;
swapchain->SetDisplayColorConversion(transform);
return true;
}
}
return false;
}
bool GfxCommandApplier::ApplySetDisplayRotationCmd(
Session* session, fuchsia::ui::gfx::SetDisplayRotationCmdHACK command) {
if (auto compositor = session->resources()->FindResource<Compositor>(command.compositor_id)) {
return compositor->SetLayoutRotation(command.rotation_degrees, session->error_reporter());
}
return false;
}
bool GfxCommandApplier::ApplySetEnableViewDebugBounds(
Session* session, fuchsia::ui::gfx::SetEnableDebugViewBoundsCmd command) {
if (auto view = session->resources()->FindResource<View>(command.view_id)) {
view->set_should_render_bounding_box(command.enable);
return true;
}
return false;
}
bool GfxCommandApplier::ApplySetViewHolderBoundsColor(
Session* session, fuchsia::ui::gfx::SetViewHolderBoundsColorCmd command) {
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;
if (auto view_holder = session->resources()->FindResource<ViewHolder>(command.view_holder_id)) {
view_holder->set_bounds_color(glm::vec4(red, green, blue, 1));
return true;
}
return false;
};
bool GfxCommandApplier::ApplyDetachCmd(Session* session, fuchsia::ui::gfx::DetachCmd command) {
if (auto resource = session->resources()->FindResource<Resource>(command.id)) {
return resource->Detach(session->error_reporter());
}
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(session->error_reporter());
}
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, session->error_reporter());
}
} else {
return node->SetTranslation(UnwrapVector3(command.value), session->error_reporter());
}
}
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, session->error_reporter());
}
} else {
return node->SetScale(UnwrapVector3(command.value), session->error_reporter());
}
}
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, session->error_reporter());
}
} else {
return node->SetRotation(UnwrapQuaternion(command.value), session->error_reporter());
}
}
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, session->error_reporter());
}
}
return node->SetAnchor(UnwrapVector3(command.value), session->error_reporter());
}
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), session->error_reporter());
}
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, session->error_reporter());
}
return false;
}
bool GfxCommandApplier::ApplySetClipPlanesCmd(Session* session,
fuchsia::ui::gfx::SetClipPlanesCmd command) {
if (auto node = session->resources()->FindResource<Node>(command.node_id)) {
std::vector<escher::plane3> clip_planes;
clip_planes.reserve(command.clip_planes.size());
for (auto& p : command.clip_planes) {
clip_planes.emplace_back(Unwrap(p.dir), p.dist);
}
return node->SetClipPlanes(std::move(clip_planes), session->error_reporter());
}
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), session->error_reporter());
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), session->error_reporter());
}
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), session->error_reporter());
}
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), session->error_reporter());
}
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::kEnableDebugging:
renderer->set_enable_debugging(command.param.enable_debugging());
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, zx::time(command.base_time),
zx::duration(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), session->error_reporter());
}
return false;
}
bool GfxCommandApplier::ApplySetPointLightPositionCmd(
Session* session, fuchsia::ui::gfx::SetPointLightPositionCmd command) {
// TODO(SCN-123): support variables.
if (command.position.variable_id) {
session->error_reporter()->ERROR()
<< "scenic_impl::gfx::GfxCommandApplier::ApplySetPointLightPositionCmd(): unimplemented: "
"variable position.";
return false;
} else if (auto light = session->resources()->FindResource<PointLight>(command.light_id)) {
return light->SetPosition(Unwrap(command.position.value));
}
return false;
}
bool GfxCommandApplier::ApplySetPointLightFalloffCmd(
Session* session, fuchsia::ui::gfx::SetPointLightFalloffCmd command) {
// TODO(SCN-123): support variables.
if (command.falloff.variable_id) {
session->error_reporter()->ERROR()
<< "scenic_impl::gfx::GfxCommandApplier::ApplySetPointLightFalloffCmd(): unimplemented: "
"variable falloff.";
return false;
} else if (auto light = session->resources()->FindResource<PointLight>(command.light_id)) {
return light->SetFalloff(command.falloff.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());
}
}
session->error_reporter()->ERROR()
<< "scenic_impl::gfx::GfxCommandApplier::ApplyAddLightCmd(): unimplemented.";
return false;
}
bool GfxCommandApplier::ApplySceneAddAmbientLightCmd(
Session* session, fuchsia::ui::gfx::SceneAddAmbientLightCmd command) {
if (auto scene = session->resources()->FindResource<Scene>(command.scene_id)) {
if (auto light = session->resources()->FindResource<AmbientLight>(command.light_id)) {
return scene->AddAmbientLight(std::move(light));
}
}
session->error_reporter()->ERROR()
<< "scenic_impl::gfx::GfxCommandApplier::ApplySceneAddAmbientLightCmd(): unimplemented.";
return false;
}
bool GfxCommandApplier::ApplySceneAddDirectionalLightCmd(
Session* session, fuchsia::ui::gfx::SceneAddDirectionalLightCmd command) {
if (auto scene = session->resources()->FindResource<Scene>(command.scene_id)) {
if (auto light = session->resources()->FindResource<DirectionalLight>(command.light_id)) {
return scene->AddDirectionalLight(std::move(light));
}
}
session->error_reporter()->ERROR()
<< "scenic_impl::gfx::GfxCommandApplier::ApplySceneAddDirectionalLightCmd(): unimplemented.";
return false;
}
bool GfxCommandApplier::ApplySceneAddPointLightCmd(
Session* session, fuchsia::ui::gfx::SceneAddPointLightCmd command) {
if (auto scene = session->resources()->FindResource<Scene>(command.scene_id)) {
if (auto light = session->resources()->FindResource<PointLight>(command.light_id)) {
return scene->AddPointLight(std::move(light));
}
}
session->error_reporter()->ERROR()
<< "scenic_impl::gfx::GfxCommandApplier::ApplySceneAddPointLightCmd(): 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->image_pipe_updater(),
session->shared_error_reporter());
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) {
// TODO(SCN-1255): temporarily disable directional light creation ASAP, so
// that people don't try to use them before we decide whether we want them.
// They are currently only used by RootPresenter and example programs.
// session->error_reporter()->ERROR()
// << "fuchsia.ui.gfx.CreateResourceCmd: DirectionalLights are
// disabled";
// return false;
auto light = CreateDirectionalLight(session, id);
return light ? session->resources()->AddResource(id, std::move(light)) : false;
}
bool GfxCommandApplier::ApplyCreatePointLight(Session* session, ResourceId id,
fuchsia::ui::gfx::PointLightArgs args) {
auto light = CreatePointLight(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;
}
// Emit a warning that the radius is too small.
// TODO(FLK-467): Convert warning to error and kill the session if the
// code enters this path.
if (args.radius.vector1() <= escher::kEpsilon) {
session->error_reporter()->WARN() << "Circle radius is too small " << args.radius.vector1();
}
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.value)
<< "scenic_impl::gfx::GfxCommandApplier::ApplyCreateView(): no token provided.";
if (auto view = CreateView(session, id, std::move(args))) {
if (!(session->SetRootView(view->As<View>()->GetWeakPtr()))) {
FXL_LOG(ERROR) << "Error: cannot set more than one root view in a session. This will soon "
"become a session-terminating error. For more info, see [SCN-1249].";
// TODO(SCN-1249) Return false and report the error in this case, and
// shut down any sessions that violate the one-view-per-session contract.
// return false;
}
view->As<View>()->Connect(); // Initiate the link.
session->resources()->AddResource(id, std::move(view));
return true;
}
return false;
}
bool GfxCommandApplier::ApplyCreateView(Session* session, ResourceId id,
fuchsia::ui::gfx::ViewArgs3 args) {
// Sanity check. We also rely on FIDL to enforce this for us, although it
// does not at the moment.
FXL_DCHECK(args.token.value)
<< "scenic_impl::gfx::GfxCommandApplier::ApplyCreateView(): no token provided.";
if (auto view = CreateView(session, id, std::move(args))) {
if (!(session->SetRootView(view->As<View>()->GetWeakPtr()))) {
FXL_LOG(ERROR) << "Error: cannot set more than one root view in a session. This will soon "
"become a session-terminating error. For more info, see [SCN-1249].";
// TODO(SCN-1249) Return false and report the error in this case, and
// shut down any sessions that violate the one-view-per-session contract.
// return false;
}
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.value)
<< "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 ViewHolder 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::OpacityNodeArgsHACK 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(session->error_reporter())->Suballocate(num_bytes, memory_offset)
: memory->GetGpuMem(session->error_reporter());
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::CreatePointLight(Session* session, ResourceId id) {
return fxl::MakeRefCounted<PointLight>(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.value), session->error_reporter());
if (!link.valid()) {
return nullptr; // Error out: link could not be registered.
}
// TODO(SCN-1410): Deprecate in favor of ViewArgs3.
fuchsia::ui::views::ViewRefControl control_ref;
fuchsia::ui::views::ViewRef view_ref;
{
// Safe and valid eventpair, by construction.
zx_status_t status = zx::eventpair::create(
/*flags*/ 0u, &control_ref.reference, &view_ref.reference);
FXL_DCHECK(status == ZX_OK);
// Remove signaling.
status = view_ref.reference.replace(ZX_RIGHTS_BASIC, &view_ref.reference);
FXL_DCHECK(status == ZX_OK);
}
// Create a View: Link was successful, view ref is valid.
return fxl::MakeRefCounted<View>(session, id, std::move(link), std::move(control_ref),
std::move(view_ref), session->shared_error_reporter(),
session->event_reporter());
}
ResourcePtr GfxCommandApplier::CreateView(Session* session, ResourceId id,
fuchsia::ui::gfx::ViewArgs3 args) {
if (!validate_viewref(args.control_ref, args.view_ref)) {
return nullptr; // Error out: view ref not usable.
}
ViewLinker* view_linker = session->session_context().view_linker;
ViewLinker::ImportLink link =
view_linker->CreateImport(std::move(args.token.value), session->error_reporter());
if (!link.valid()) {
return nullptr; // Error out: link could not be registered.
}
// Create a View: Link was successful, view ref is valid.
return fxl::MakeRefCounted<View>(session, id, std::move(link), std::move(args.control_ref),
std::move(args.view_ref), session->shared_error_reporter(),
session->event_reporter());
}
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.value), 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::OpacityNodeArgsHACK 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) {
FXL_DCHECK(session->session_context().display_manager);
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().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) {
// 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};
// TODO(SCN-1429) - Once we remove the default rounded rect that is created
// from the factory and instead just use the mesh generated by the paper
// shape cache, then this will just become the standard code path.
escher::MeshPtr mesh;
auto factory = session->session_context().escher_rounded_rect_factory;
if (factory && command_context->batch_gpu_uploader()) {
mesh = factory->NewRoundedRect(rect_spec, mesh_spec, command_context->batch_gpu_uploader());
}
return fxl::MakeRefCounted<RoundedRectangleShape>(session, id, rect_spec, mesh);
}
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