| // Copyright 2017 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/bin/guest/vmm/device/guest_view.h" |
| |
| #include <lib/fxl/logging.h> |
| #include <lib/images/cpp/images.h> |
| |
| GuestView::GuestView( |
| scenic::ViewContext view_context, |
| fidl::InterfaceHandle<fuchsia::guest::device::ViewListener> view_listener, |
| GpuScanout* scanout) |
| : BaseView(std::move(view_context), "Guest"), |
| background_(session()), |
| material_(session()), |
| scanout_(*scanout), |
| view_listener_(view_listener.Bind()) { |
| view().AddChild(background_); |
| background_.SetMaterial(material_); |
| |
| // Request hard key events be delivered to the view. |
| fuchsia::ui::input::Command command; |
| command.set_set_hard_keyboard_delivery({ .delivery_request = true }); |
| session()->Enqueue(std::move(command)); |
| |
| scanout_.SetFlushHandler( |
| [this](virtio_gpu_rect_t rect) { InvalidateScene(); }); |
| scanout_.SetUpdateSourceHandler([this](uint32_t width, uint32_t height) { |
| scanout_source_width_ = width; |
| scanout_source_height_ = height; |
| InvalidateScene(); |
| }); |
| } |
| |
| void GuestView::OnSceneInvalidated( |
| fuchsia::images::PresentationInfo presentation_info) { |
| if (!has_logical_size() || !has_physical_size()) { |
| return; |
| } |
| if (static_cast<uint32_t>(physical_size().x) != image_info_.width || |
| static_cast<uint32_t>(physical_size().y) != image_info_.height) { |
| image_info_.width = physical_size().x; |
| image_info_.height = physical_size().y; |
| image_info_.stride = image_info_.width * 4; |
| image_info_.pixel_format = fuchsia::images::PixelFormat::BGRA_8; |
| |
| // Allocate a framebuffer and attach it as a GPU scanout. |
| zx::vmo scanout_vmo; |
| auto vmo_size = images::ImageSize(image_info_); |
| zx_status_t status = zx::vmo::create(vmo_size, 0, &scanout_vmo); |
| FXL_CHECK(status == ZX_OK) |
| << "Scanout target VMO creation failed " << status; |
| zx::vmo scenic_vmo; |
| status = scanout_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &scenic_vmo); |
| FXL_CHECK(status == ZX_OK) |
| << "Scanout target VMO duplication failed " << status; |
| memory_ = std::make_unique<scenic::Memory>( |
| session(), std::move(scenic_vmo), vmo_size, |
| fuchsia::images::MemoryType::HOST_MEMORY); |
| |
| status = scanout_.SetFlushTarget(std::move(scanout_vmo), vmo_size, |
| image_info_.width, image_info_.height, |
| image_info_.stride); |
| FXL_CHECK(status == ZX_OK) << "Scanout target VMO flush failed " << status; |
| } |
| |
| const float width = logical_size().x; |
| const float height = logical_size().y; |
| scenic::Rectangle shape(session(), width, height); |
| background_.SetShape(shape); |
| const float center_x = width * .5f; |
| const float center_y = height * .5f; |
| const float scale_x = |
| static_cast<float>(image_info_.width) / scanout_source_width_; |
| const float scale_y = |
| static_cast<float>(image_info_.height) / scanout_source_height_; |
| |
| // Scale the background node such that the scanout resource sub-region |
| // matches the image size. Ideally, this would just be a scale transform of |
| // the material itself. |
| // TODO(SCN-958): Materials should support transforms |
| background_.SetAnchor(-center_x, -center_y, 0.0f); |
| background_.SetTranslation(center_x, center_y, 0.0f); |
| background_.SetScale(scale_x, scale_y, 1.0f); |
| |
| scenic::Image image(*memory_, 0u, image_info_); |
| material_.SetTexture(image); |
| } |
| |
| void GuestView::OnPropertiesChanged( |
| fuchsia::ui::gfx::ViewProperties old_properties) { |
| view_listener_->OnSizeChanged(logical_size()); |
| } |
| |
| void GuestView::OnInputEvent(fuchsia::ui::input::InputEvent event) { |
| view_listener_->OnInputEvent(std::move(event)); |
| } |
| |
| void GuestView::OnScenicError(std::string error) { |
| FXL_LOG(ERROR) << "Scenic session failed " << error; |
| } |