// // Copyright 2019 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // ScenicWindow.cpp: // Implements methods from ScenicWindow // #include "util/fuchsia/ScenicWindow.h" #include #include #include #include #include #include #include #include #include #include namespace { async::Loop *GetDefaultLoop() { static async::Loop *defaultLoop = new async::Loop(&kAsyncLoopConfigNeverAttachToThread); return defaultLoop; } zx::channel ConnectToServiceRoot() { zx::channel clientChannel; zx::channel serverChannel; zx_status_t result = zx::channel::create(0, &clientChannel, &serverChannel); ASSERT(result == ZX_OK); result = fdio_service_connect("/svc/.", serverChannel.release()); ASSERT(result == ZX_OK); return clientChannel; } template zx_status_t ConnectToService(zx_handle_t serviceRoot, fidl::InterfaceRequest request) { ASSERT(request.is_valid()); return fdio_service_connect_at(serviceRoot, Interface::Name_, request.TakeChannel().release()); } template fidl::InterfacePtr ConnectToService(zx_handle_t serviceRoot, async_dispatcher_t *dispatcher) { fidl::InterfacePtr result; ConnectToService(serviceRoot, result.NewRequest(dispatcher)); return result; } } // namespace ScenicWindow::ScenicWindow() : mLoop(GetDefaultLoop()), mServiceRoot(ConnectToServiceRoot()), mScenic( ConnectToService(mServiceRoot.get(), mLoop->dispatcher())), mPresenter(ConnectToService(mServiceRoot.get(), mLoop->dispatcher())), mScenicSession(mScenic.get(), mLoop->dispatcher()), mShape(&mScenicSession), mMaterial(&mScenicSession) { mScenicSession.set_error_handler(fit::bind_member(this, &ScenicWindow::onScenicError)); mScenicSession.set_event_handler(fit::bind_member(this, &ScenicWindow::onScenicEvents)); mScenicSession.set_on_frame_presented_handler( fit::bind_member(this, &ScenicWindow::onFramePresented)); } ScenicWindow::~ScenicWindow() { destroy(); } bool ScenicWindow::initializeImpl(const std::string &name, int width, int height) { // Set up scenic resources. mShape.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask); mShape.SetMaterial(mMaterial); fuchsia::ui::views::ViewToken viewToken; fuchsia::ui::views::ViewHolderToken viewHolderToken; std::tie(viewToken, viewHolderToken) = scenic::NewViewTokenPair(); // Create view. mView = std::make_unique(&mScenicSession, std::move(viewToken), name); mView->AddChild(mShape); // Present view. mPresenter->PresentOrReplaceView(std::move(viewHolderToken), nullptr); mWidth = width; mHeight = height; resetNativeWindow(); // Block until initial view dimensions are known. while (!mHasViewMetrics && !mHasViewProperties && !mLostSession) { mLoop->ResetQuit(); mLoop->Run(zx::time::infinite(), true /* once */); } return true; } void ScenicWindow::disableErrorMessageDialog() {} void ScenicWindow::destroy() { while (mInFlightPresents != 0 && !mLostSession) { mLoop->ResetQuit(); mLoop->Run(); } ASSERT(mInFlightPresents == 0 || mLostSession); mFuchsiaEGLWindow.reset(); } void ScenicWindow::resetNativeWindow() { fuchsia::images::ImagePipe2Ptr imagePipe; uint32_t imagePipeId = mScenicSession.AllocResourceId(); mScenicSession.Enqueue( scenic::NewCreateImagePipe2Cmd(imagePipeId, imagePipe.NewRequest(mLoop->dispatcher()))); zx_handle_t imagePipeHandle = imagePipe.Unbind().TakeChannel().release(); mMaterial.SetTexture(imagePipeId); mScenicSession.ReleaseResource(imagePipeId); present(); mFuchsiaEGLWindow.reset(fuchsia_egl_window_create(imagePipeHandle, mWidth, mHeight)); } EGLNativeWindowType ScenicWindow::getNativeWindow() const { return reinterpret_cast(mFuchsiaEGLWindow.get()); } EGLNativeDisplayType ScenicWindow::getNativeDisplay() const { return EGL_DEFAULT_DISPLAY; } void ScenicWindow::messageLoop() { mLoop->ResetQuit(); mLoop->RunUntilIdle(); } void ScenicWindow::setMousePosition(int x, int y) { UNIMPLEMENTED(); } bool ScenicWindow::setOrientation(int width, int height) { UNIMPLEMENTED(); return false; } bool ScenicWindow::setPosition(int x, int y) { UNIMPLEMENTED(); return false; } bool ScenicWindow::resize(int width, int height) { mWidth = width; mHeight = height; fuchsia_egl_window_resize(mFuchsiaEGLWindow.get(), width, height); mViewSizeDirty = true; updateViewSize(); return true; } void ScenicWindow::setVisible(bool isVisible) {} void ScenicWindow::signalTestEvent() {} void ScenicWindow::present() { while (mInFlightPresents >= kMaxInFlightPresents && !mLostSession) { mLoop->ResetQuit(); mLoop->Run(); } if (mLostSession) { return; } ASSERT(mInFlightPresents < kMaxInFlightPresents); ++mInFlightPresents; mScenicSession.Present2(0, 0, [](fuchsia::scenic::scheduling::FuturePresentationTimes info) {}); } void ScenicWindow::onFramePresented(fuchsia::scenic::scheduling::FramePresentedInfo info) { mInFlightPresents -= info.presentation_infos.size(); ASSERT(mInFlightPresents >= 0); mLoop->Quit(); } void ScenicWindow::onScenicEvents(std::vector events) { for (const auto &event : events) { if (event.is_gfx()) { if (event.gfx().is_metrics()) { if (event.gfx().metrics().node_id != mShape.id()) continue; onViewMetrics(event.gfx().metrics().metrics); } else if (event.gfx().is_view_properties_changed()) { if (event.gfx().view_properties_changed().view_id != mView->id()) continue; onViewProperties(event.gfx().view_properties_changed().properties); } } } if (mViewSizeDirty) { updateViewSize(); } } void ScenicWindow::onScenicError(zx_status_t status) { WARN() << "OnScenicError: " << zx_status_get_string(status); mLostSession = true; mLoop->Quit(); } void ScenicWindow::onViewMetrics(const fuchsia::ui::gfx::Metrics &metrics) { mDisplayScaleX = metrics.scale_x; mDisplayScaleY = metrics.scale_y; mHasViewMetrics = true; mViewSizeDirty = true; } void ScenicWindow::onViewProperties(const fuchsia::ui::gfx::ViewProperties &properties) { float width = properties.bounding_box.max.x - properties.bounding_box.min.x - properties.inset_from_min.x - properties.inset_from_max.x; float height = properties.bounding_box.max.y - properties.bounding_box.min.y - properties.inset_from_min.y - properties.inset_from_max.y; mDisplayWidthDips = width; mDisplayHeightDips = height; mHasViewProperties = true; mViewSizeDirty = true; } void ScenicWindow::updateViewSize() { if (!mViewSizeDirty || !mHasViewMetrics || !mHasViewProperties) { return; } mViewSizeDirty = false; // Surface size in pixels is // (mWidth, mHeight) // // View size in pixels is // (mDisplayWidthDips * mDisplayScaleX) x (mDisplayHeightDips * mDisplayScaleY) float widthDips = mWidth / mDisplayScaleX; float heightDips = mHeight / mDisplayScaleY; mShape.SetShape(scenic::Rectangle(&mScenicSession, widthDips, heightDips)); mShape.SetTranslation(0.5f * widthDips, 0.5f * heightDips, 0.f); present(); } // static OSWindow *OSWindow::New() { return new ScenicWindow; }