Added initial support for displaying on Wayland compositors.
[vuplus_xbmc] / xbmc / windowing / egl / wayland / XBMCSurface.cpp
1 /*
2  *      Copyright (C) 2011-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20 #include <sstream>
21 #include <stdexcept>
22
23 #include <boost/bind.hpp>
24 #include <boost/function.hpp>
25 #include <boost/scoped_ptr.hpp>
26
27 #include <wayland-client.h>
28
29 #include "windowing/DllWaylandClient.h"
30 #include "windowing/DllWaylandEgl.h"
31
32 #include "Callback.h"
33 #include "Compositor.h"
34 #include "OpenGLSurface.h"
35 #include "Region.h"
36 #include "Shell.h"
37 #include "ShellSurface.h"
38 #include "Surface.h"
39
40 #include "windowing/WaylandProtocol.h"
41 #include "XBMCSurface.h"
42
43 namespace xbmc
44 {
45 namespace wayland
46 {
47 class XBMCSurface::Private
48 {
49 public:
50
51   Private(IDllWaylandClient &clientLibrary,
52           IDllWaylandEGL &eglLibrary,
53           const boost::scoped_ptr<Compositor> &compositor,
54           const boost::scoped_ptr<Shell> &shell,
55           uint32_t width,
56           uint32_t height);
57
58   typedef boost::function<struct wl_region * ()> RegionFactory;
59
60   IDllWaylandClient &m_clientLibrary;
61   IDllWaylandEGL &m_eglLibrary;
62
63   /* We only care about xbmc::Compositor's CreateRegion function
64    * and don't want to store a pointer to the compositor to create
65    * a region later */ 
66   RegionFactory m_regionFactory;
67
68   boost::scoped_ptr<Surface> m_surface;
69   boost::scoped_ptr<ShellSurface> m_shellSurface;
70   boost::scoped_ptr<OpenGLSurface> m_glSurface;
71   boost::scoped_ptr<Callback> m_frameCallback;
72   
73   void OnFrameCallback(uint32_t);
74   void AddFrameCallback();
75 };
76 }
77 }
78
79 namespace xw = xbmc::wayland;
80
81 /* Creating a new xbmc::wayland::XBMCSurface effectively creates
82  * an OpenGL ES bindable EGL Window and a corresponding 
83  * surface object for the compositor to display it on-screen. It also
84  * creates a "shell surface", which is a special extension to a normal
85  * surface which adds window-management functionality to a surface.
86  * 
87  * If there are any errors in creating the surface they will be thrown
88  * as std::runtime_errors and the object that creates this one
89  * needs to handle catching them.
90  */
91 xw::XBMCSurface::Private::Private(IDllWaylandClient &clientLibrary,
92                                   IDllWaylandEGL &eglLibrary,
93                                   const boost::scoped_ptr<Compositor> &compositor,
94                                   const boost::scoped_ptr<Shell> &shell,
95                                   uint32_t width,
96                                   uint32_t height) :
97   m_clientLibrary(clientLibrary),
98   m_eglLibrary(eglLibrary),
99   m_regionFactory(boost::bind(&Compositor::CreateRegion,
100                               compositor.get())),
101   m_surface(new xw::Surface(m_clientLibrary,
102                             compositor->CreateSurface())),
103   m_shellSurface(new xw::ShellSurface(m_clientLibrary,
104                                       shell->CreateShellSurface(
105                                         m_surface->GetWlSurface()))),
106   /* Creating a new xbmc::wayland::OpenGLSurface will manage the
107    * attach-and-commit process on eglSwapBuffers */
108   m_glSurface(new xw::OpenGLSurface(m_eglLibrary,
109                                     m_surface->GetWlSurface(),
110                                     width,
111                                     height))
112 {
113   /* SetOpaqueRegion here is an important optimization for the
114    * compositor. It effectively tells it that this window is completely
115    * opaque. This means that the window can be rendered without
116    * the use of GL_BLEND which represents a substantial rendering
117    * speedup, especially for larger surfaces. It also means that
118    * this window can be placed in an overlay plane, so it can
119    * skip compositing alltogether */
120   xw::Region region(m_clientLibrary, m_regionFactory());
121   
122   region.AddRectangle(0, 0, 640, 480);
123   
124   m_surface->SetOpaqueRegion(region.GetWlRegion());
125   m_surface->Commit();
126   
127   /* The compositor is responsible for letting us know when to
128    * draw things. This is effectively to conserve battery life
129    * where drawing our surface would be a futile operation. Its not
130    * entirely applicable to the xbmc case because we use a game loop,
131    * but some compositor expect it, so we must add a frame callback
132    * as soon as the surface is ready to be rendered to */ 
133   AddFrameCallback();
134 }
135
136 xw::XBMCSurface::XBMCSurface(IDllWaylandClient &clientLibrary,
137                              IDllWaylandEGL &eglLibrary,
138                              const boost::scoped_ptr<Compositor> &compositor,
139                              const boost::scoped_ptr<Shell> &shell,
140                              uint32_t width,
141                              uint32_t height) :
142   priv(new Private(clientLibrary,
143                    eglLibrary,
144                    compositor,
145                    shell,
146                    width,
147                    height))
148 {
149 }
150
151 /* A defined destructor is required such that
152  * boost::scoped_ptr<Private>::~scoped_ptr is generated here */
153 xw::XBMCSurface::~XBMCSurface()
154 {
155 }
156
157 void
158 xw::XBMCSurface::Show()
159 {
160   protocol::CallMethodOnWaylandObject(priv->m_clientLibrary,
161                                       priv->m_shellSurface->GetWlShellSurface(),
162                                       WL_SHELL_SURFACE_SET_TOPLEVEL);
163 }
164
165 void
166 xw::XBMCSurface::Resize(uint32_t width, uint32_t height)
167 {
168   /* Since the xbmc::wayland::OpenGLSurface owns the buffer, it is
169    * responsible for changing its size. When the size changes, the
170    * opaque region must also change */
171   priv->m_glSurface->Resize(width, height);
172   
173   xw::Region region(priv->m_clientLibrary,
174                     priv->m_regionFactory());
175   
176   region.AddRectangle(0, 0, width, height);
177   
178   priv->m_surface->SetOpaqueRegion(region.GetWlRegion());
179   priv->m_surface->Commit();
180 }
181
182 EGLNativeWindowType *
183 xw::XBMCSurface::EGLNativeWindow() const
184 {
185   return priv->m_glSurface->GetEGLNativeWindow();
186 }
187
188 void xw::XBMCSurface::Private::OnFrameCallback(uint32_t time)
189 {
190   AddFrameCallback();
191 }
192
193 void xw::XBMCSurface::Private::AddFrameCallback()
194 {
195   m_frameCallback.reset(new xw::Callback(m_clientLibrary,
196                                          m_surface->CreateFrameCallback(),
197                                          boost::bind(&Private::OnFrameCallback,
198                                                      this,
199                                                      _1)));
200 }