• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ScenicWindow.cpp:
7 //    Implements methods from ScenicWindow
8 //
9 
10 #include "util/fuchsia/ScenicWindow.h"
11 
12 #include <fuchsia/images/cpp/fidl.h>
13 #include <fuchsia/ui/views/cpp/fidl.h>
14 #include <lib/async-loop/cpp/loop.h>
15 #include <lib/async-loop/default.h>
16 #include <lib/fdio/directory.h>
17 #include <lib/fidl/cpp/interface_ptr.h>
18 #include <lib/fidl/cpp/interface_request.h>
19 #include <lib/ui/scenic/cpp/view_token_pair.h>
20 #include <lib/zx/channel.h>
21 #include <zircon/status.h>
22 
23 #include "common/debug.h"
24 
25 namespace
26 {
27 
GetDefaultLoop()28 async::Loop *GetDefaultLoop()
29 {
30     static async::Loop *defaultLoop = new async::Loop(&kAsyncLoopConfigNeverAttachToThread);
31     return defaultLoop;
32 }
33 
ConnectToServiceRoot()34 zx::channel ConnectToServiceRoot()
35 {
36     zx::channel clientChannel;
37     zx::channel serverChannel;
38     zx_status_t result = zx::channel::create(0, &clientChannel, &serverChannel);
39     ASSERT(result == ZX_OK);
40     result = fdio_service_connect("/svc/.", serverChannel.release());
41     ASSERT(result == ZX_OK);
42     return clientChannel;
43 }
44 
45 template <typename Interface>
ConnectToService(zx_handle_t serviceRoot,fidl::InterfaceRequest<Interface> request)46 zx_status_t ConnectToService(zx_handle_t serviceRoot, fidl::InterfaceRequest<Interface> request)
47 {
48     ASSERT(request.is_valid());
49     return fdio_service_connect_at(serviceRoot, Interface::Name_, request.TakeChannel().release());
50 }
51 
52 template <typename Interface>
ConnectToService(zx_handle_t serviceRoot,async_dispatcher_t * dispatcher)53 fidl::InterfacePtr<Interface> ConnectToService(zx_handle_t serviceRoot,
54                                                async_dispatcher_t *dispatcher)
55 {
56     fidl::InterfacePtr<Interface> result;
57     ConnectToService(serviceRoot, result.NewRequest(dispatcher));
58     return result;
59 }
60 
61 }  // namespace
62 
ScenicWindow()63 ScenicWindow::ScenicWindow()
64     : mLoop(GetDefaultLoop()),
65       mServiceRoot(ConnectToServiceRoot()),
66       mScenic(
67           ConnectToService<fuchsia::ui::scenic::Scenic>(mServiceRoot.get(), mLoop->dispatcher())),
68       mPresenter(ConnectToService<fuchsia::ui::policy::Presenter>(mServiceRoot.get(),
69                                                                   mLoop->dispatcher())),
70       mScenicSession(mScenic.get(), mLoop->dispatcher()),
71       mShape(&mScenicSession),
72       mMaterial(&mScenicSession)
73 {
74     mScenicSession.set_error_handler(fit::bind_member(this, &ScenicWindow::onScenicError));
75     mScenicSession.set_event_handler(fit::bind_member(this, &ScenicWindow::onScenicEvents));
76     mScenicSession.set_on_frame_presented_handler(
77         fit::bind_member(this, &ScenicWindow::onFramePresented));
78 }
79 
~ScenicWindow()80 ScenicWindow::~ScenicWindow()
81 {
82     destroy();
83 }
84 
initialize(const std::string & name,int width,int height)85 bool ScenicWindow::initialize(const std::string &name, int width, int height)
86 {
87     // Set up scenic resources.
88     mShape.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask);
89     mShape.SetMaterial(mMaterial);
90 
91     fuchsia::ui::views::ViewToken viewToken;
92     fuchsia::ui::views::ViewHolderToken viewHolderToken;
93     std::tie(viewToken, viewHolderToken) = scenic::NewViewTokenPair();
94 
95     // Create view.
96     mView = std::make_unique<scenic::View>(&mScenicSession, std::move(viewToken), name);
97     mView->AddChild(mShape);
98 
99     // Present view.
100     mPresenter->PresentOrReplaceView(std::move(viewHolderToken), nullptr);
101 
102     mWidth  = width;
103     mHeight = height;
104 
105     resetNativeWindow();
106 
107     // Block until initial view dimensions are known.
108     while (!mHasViewMetrics && !mHasViewProperties && !mLostSession)
109     {
110         mLoop->ResetQuit();
111         mLoop->Run(zx::time::infinite(), true /* once */);
112     }
113 
114     return true;
115 }
116 
destroy()117 void ScenicWindow::destroy()
118 {
119     while (mInFlightPresents != 0 && !mLostSession)
120     {
121         mLoop->ResetQuit();
122         mLoop->Run();
123     }
124 
125     ASSERT(mInFlightPresents == 0 || mLostSession);
126 
127     mFuchsiaEGLWindow.reset();
128 }
129 
resetNativeWindow()130 void ScenicWindow::resetNativeWindow()
131 {
132     fuchsia::images::ImagePipe2Ptr imagePipe;
133     uint32_t imagePipeId = mScenicSession.AllocResourceId();
134     mScenicSession.Enqueue(
135         scenic::NewCreateImagePipe2Cmd(imagePipeId, imagePipe.NewRequest(mLoop->dispatcher())));
136     zx_handle_t imagePipeHandle = imagePipe.Unbind().TakeChannel().release();
137 
138     mMaterial.SetTexture(imagePipeId);
139     mScenicSession.ReleaseResource(imagePipeId);
140     present();
141 
142     mFuchsiaEGLWindow.reset(fuchsia_egl_window_create(imagePipeHandle, mWidth, mHeight));
143 }
144 
getNativeWindow() const145 EGLNativeWindowType ScenicWindow::getNativeWindow() const
146 {
147     return reinterpret_cast<EGLNativeWindowType>(mFuchsiaEGLWindow.get());
148 }
149 
getNativeDisplay() const150 EGLNativeDisplayType ScenicWindow::getNativeDisplay() const
151 {
152     return EGL_DEFAULT_DISPLAY;
153 }
154 
messageLoop()155 void ScenicWindow::messageLoop()
156 {
157     mLoop->ResetQuit();
158     mLoop->RunUntilIdle();
159 }
160 
setMousePosition(int x,int y)161 void ScenicWindow::setMousePosition(int x, int y)
162 {
163     UNIMPLEMENTED();
164 }
165 
setPosition(int x,int y)166 bool ScenicWindow::setPosition(int x, int y)
167 {
168     UNIMPLEMENTED();
169     return false;
170 }
171 
resize(int width,int height)172 bool ScenicWindow::resize(int width, int height)
173 {
174     mWidth  = width;
175     mHeight = height;
176 
177     fuchsia_egl_window_resize(mFuchsiaEGLWindow.get(), width, height);
178 
179     mViewSizeDirty = true;
180 
181     updateViewSize();
182 
183     return true;
184 }
185 
setVisible(bool isVisible)186 void ScenicWindow::setVisible(bool isVisible) {}
187 
signalTestEvent()188 void ScenicWindow::signalTestEvent() {}
189 
present()190 void ScenicWindow::present()
191 {
192     while (mInFlightPresents >= kMaxInFlightPresents && !mLostSession)
193     {
194         mLoop->ResetQuit();
195         mLoop->Run();
196     }
197 
198     if (mLostSession)
199     {
200         return;
201     }
202 
203     ASSERT(mInFlightPresents < kMaxInFlightPresents);
204 
205     ++mInFlightPresents;
206     mScenicSession.Present2(0, 0, [](fuchsia::scenic::scheduling::FuturePresentationTimes info) {});
207 }
208 
onFramePresented(fuchsia::scenic::scheduling::FramePresentedInfo info)209 void ScenicWindow::onFramePresented(fuchsia::scenic::scheduling::FramePresentedInfo info)
210 {
211     mInFlightPresents -= info.presentation_infos.size();
212     ASSERT(mInFlightPresents >= 0);
213     mLoop->Quit();
214 }
215 
onScenicEvents(std::vector<fuchsia::ui::scenic::Event> events)216 void ScenicWindow::onScenicEvents(std::vector<fuchsia::ui::scenic::Event> events)
217 {
218     for (const auto &event : events)
219     {
220         if (event.is_gfx())
221         {
222             if (event.gfx().is_metrics())
223             {
224                 if (event.gfx().metrics().node_id != mShape.id())
225                     continue;
226                 onViewMetrics(event.gfx().metrics().metrics);
227             }
228             else if (event.gfx().is_view_properties_changed())
229             {
230                 if (event.gfx().view_properties_changed().view_id != mView->id())
231                     continue;
232                 onViewProperties(event.gfx().view_properties_changed().properties);
233             }
234         }
235     }
236 
237     if (mViewSizeDirty)
238     {
239         updateViewSize();
240     }
241 }
242 
onScenicError(zx_status_t status)243 void ScenicWindow::onScenicError(zx_status_t status)
244 {
245     WARN() << "OnScenicError: " << zx_status_get_string(status);
246     mLostSession = true;
247     mLoop->Quit();
248 }
249 
onViewMetrics(const fuchsia::ui::gfx::Metrics & metrics)250 void ScenicWindow::onViewMetrics(const fuchsia::ui::gfx::Metrics &metrics)
251 {
252     mDisplayScaleX = metrics.scale_x;
253     mDisplayScaleY = metrics.scale_y;
254 
255     mHasViewMetrics = true;
256     mViewSizeDirty  = true;
257 }
258 
onViewProperties(const fuchsia::ui::gfx::ViewProperties & properties)259 void ScenicWindow::onViewProperties(const fuchsia::ui::gfx::ViewProperties &properties)
260 {
261     float width = properties.bounding_box.max.x - properties.bounding_box.min.x -
262                   properties.inset_from_min.x - properties.inset_from_max.x;
263     float height = properties.bounding_box.max.y - properties.bounding_box.min.y -
264                    properties.inset_from_min.y - properties.inset_from_max.y;
265 
266     mDisplayWidthDips  = width;
267     mDisplayHeightDips = height;
268 
269     mHasViewProperties = true;
270     mViewSizeDirty     = true;
271 }
272 
updateViewSize()273 void ScenicWindow::updateViewSize()
274 {
275     if (!mViewSizeDirty || !mHasViewMetrics || !mHasViewProperties)
276     {
277         return;
278     }
279 
280     mViewSizeDirty = false;
281 
282     // Surface size in pixels is
283     //   (mWidth, mHeight)
284     //
285     // View size in pixels is
286     //   (mDisplayWidthDips * mDisplayScaleX) x (mDisplayHeightDips * mDisplayScaleY)
287 
288     float widthDips  = mWidth / mDisplayScaleX;
289     float heightDips = mHeight / mDisplayScaleY;
290 
291     mShape.SetShape(scenic::Rectangle(&mScenicSession, widthDips, heightDips));
292     mShape.SetTranslation(0.5f * widthDips, 0.5f * heightDips, 0.f);
293     present();
294 }
295 
296 // static
New()297 OSWindow *OSWindow::New()
298 {
299     return new ScenicWindow;
300 }
301