You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
307 lines
8.1 KiB
307 lines
8.1 KiB
//
|
|
// 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 <fuchsia/images/cpp/fidl.h>
|
|
#include <fuchsia/ui/views/cpp/fidl.h>
|
|
#include <lib/async-loop/cpp/loop.h>
|
|
#include <lib/async-loop/default.h>
|
|
#include <lib/fdio/directory.h>
|
|
#include <lib/fidl/cpp/interface_ptr.h>
|
|
#include <lib/fidl/cpp/interface_request.h>
|
|
#include <lib/ui/scenic/cpp/view_token_pair.h>
|
|
#include <lib/zx/channel.h>
|
|
#include <zircon/status.h>
|
|
|
|
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 <typename Interface>
|
|
zx_status_t ConnectToService(zx_handle_t serviceRoot, fidl::InterfaceRequest<Interface> request)
|
|
{
|
|
ASSERT(request.is_valid());
|
|
return fdio_service_connect_at(serviceRoot, Interface::Name_, request.TakeChannel().release());
|
|
}
|
|
|
|
template <typename Interface>
|
|
fidl::InterfacePtr<Interface> ConnectToService(zx_handle_t serviceRoot,
|
|
async_dispatcher_t *dispatcher)
|
|
{
|
|
fidl::InterfacePtr<Interface> result;
|
|
ConnectToService(serviceRoot, result.NewRequest(dispatcher));
|
|
return result;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
ScenicWindow::ScenicWindow()
|
|
: mLoop(GetDefaultLoop()),
|
|
mServiceRoot(ConnectToServiceRoot()),
|
|
mScenic(
|
|
ConnectToService<fuchsia::ui::scenic::Scenic>(mServiceRoot.get(), mLoop->dispatcher())),
|
|
mPresenter(ConnectToService<fuchsia::ui::policy::Presenter>(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<scenic::View>(&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<EGLNativeWindowType>(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<fuchsia::ui::scenic::Event> 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;
|
|
}
|