Mir

Merge lp:~cemil-azizoglu/mir/mir-on-x into lp:mir

Proposed by Cemil Azizoglu
Status: Merged
Approved by: Cemil Azizoglu
Approved revision: no longer in the source branch.
Merged at revision: 2769
Proposed branch: lp:~cemil-azizoglu/mir/mir-on-x
Merge into: lp:mir
Prerequisite: lp:~cemil-azizoglu/mir/use-options-on-probing
Diff against target: 3224 lines (+2433/-85)
56 files modified
CMakeLists.txt (+6/-3)
src/platforms/CMakeLists.txt (+2/-2)
src/platforms/mesa/server/CMakeLists.txt (+3/-0)
src/platforms/mesa/server/common/buffer_allocator.cpp (+105/-18)
src/platforms/mesa/server/common/buffer_allocator.h (+9/-1)
src/platforms/mesa/server/common/display_helpers.cpp (+28/-17)
src/platforms/mesa/server/common/display_helpers.h (+8/-1)
src/platforms/mesa/server/common/ipc_operations.cpp (+4/-5)
src/platforms/mesa/server/common/ipc_operations.h (+2/-2)
src/platforms/mesa/server/kms/guest_platform.cpp (+2/-2)
src/platforms/mesa/server/kms/platform.cpp (+5/-4)
src/platforms/mesa/server/x11/CMakeLists.txt (+61/-0)
src/platforms/mesa/server/x11/display.cpp (+274/-0)
src/platforms/mesa/server/x11/display.h (+131/-0)
src/platforms/mesa/server/x11/display_buffer.cpp (+68/-0)
src/platforms/mesa/server/x11/display_buffer.h (+59/-0)
src/platforms/mesa/server/x11/display_configuration.cpp (+63/-0)
src/platforms/mesa/server/x11/display_configuration.h (+52/-0)
src/platforms/mesa/server/x11/display_group.cpp (+42/-0)
src/platforms/mesa/server/x11/display_group.h (+51/-0)
src/platforms/mesa/server/x11/gl_context.cpp (+45/-0)
src/platforms/mesa/server/x11/gl_context.h (+52/-0)
src/platforms/mesa/server/x11/input/dispatchable.cpp (+132/-0)
src/platforms/mesa/server/x11/input/dispatchable.h (+52/-0)
src/platforms/mesa/server/x11/input/input.cpp (+60/-0)
src/platforms/mesa/server/x11/input/input_device.cpp (+54/-0)
src/platforms/mesa/server/x11/input/input_device.h (+66/-0)
src/platforms/mesa/server/x11/input/input_platform.cpp (+51/-0)
src/platforms/mesa/server/x11/input/input_platform.h (+60/-0)
src/platforms/mesa/server/x11/platform.cpp (+135/-0)
src/platforms/mesa/server/x11/platform.h (+61/-0)
src/platforms/mesa/server/x11/symbols.map (+18/-0)
src/platforms/mesa/server/x11/xserver_connection.h (+47/-0)
tests/CMakeLists.txt (+4/-0)
tests/acceptance-tests/test_client_library.cpp (+10/-10)
tests/include/mir/test/doubles/mock_input_sink.h (+44/-0)
tests/include/mir/test/doubles/mock_x11.h (+78/-0)
tests/mir_test_doubles/CMakeLists.txt (+6/-0)
tests/mir_test_doubles/mock_x11.cpp (+133/-0)
tests/mir_test_doubles/platform_factory.cpp (+9/-1)
tests/mir_test_doubles/stub_buffer.cpp (+3/-3)
tests/mir_test_framework/stubbed_graphics_platform.cpp (+2/-2)
tests/unit-tests/CMakeLists.txt (+8/-2)
tests/unit-tests/client/CMakeLists.txt (+1/-1)
tests/unit-tests/graphics/CMakeLists.txt (+10/-5)
tests/unit-tests/graphics/mesa/CMakeLists.txt (+4/-0)
tests/unit-tests/graphics/mesa/common/CMakeLists.txt (+0/-2)
tests/unit-tests/graphics/mesa/common/test_drm_helper.cpp (+1/-1)
tests/unit-tests/graphics/mesa/kms/CMakeLists.txt (+2/-0)
tests/unit-tests/graphics/mesa/kms/test_buffer_allocator.cpp (+3/-2)
tests/unit-tests/graphics/mesa/kms/test_gbm_buffer.cpp (+1/-1)
tests/unit-tests/graphics/mesa/x11/CMakeLists.txt (+6/-0)
tests/unit-tests/graphics/mesa/x11/test_display.cpp (+101/-0)
tests/unit-tests/graphics/mesa/x11/test_platform.cpp (+125/-0)
tests/unit-tests/input/CMakeLists.txt (+6/-0)
tests/unit-tests/input/test_x11_dispatchable.cpp (+68/-0)
To merge this branch: bzr merge lp:~cemil-azizoglu/mir/mir-on-x
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Kevin DuBois (community) Approve
Alan Griffiths Approve
Alexandros Frantzis (community) Approve
Robert Carr (community) Approve
Chris Halse Rogers Approve
Cemil Azizoglu Pending
Review via email: mp+265163@code.launchpad.net

This proposal supersedes a proposal from 2015-07-09.

Commit message

Add X as a platform so Mir server and clients can be run under X11.

Description of the change

Add X as a platform so Mir server and clients can be run under X11.

To run the server-side, use (no need to be root):
bin/mir_demo_server --platform-input-lib lib/server-modules/server-
mesa-x11.so.3

Running a client is exactly the same as Mesa (except you don't need to be root), as mir-on-x is a server-side only notion.

There is still a lot of work to do depending on how far we want to go. Since this platform is mostly intended for developers (as opposed to end-users), we can refine as we go.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

Some high level first impressions:

~~~~~~~~~

The automatic module detection doesn't work correctly. In case of a priority tie, the first module found (in filesystem order) is selected. If that module is mesa-kms then mesa-x11 can never be loaded unless forced with the platform-graphics-lib option. We need to change mesa-kms and/or mesa-x11 to report different priorities depending on the environment.

~~~~~~~~~

I can't get any output on intel for EGL clients and only the first frame for software clients (I think these are known issues?).

~~~~~~~~~

196 + bool const use_dma_buf_extension)

It's better to use an enum for readability, since true/false values are very uninformative, e.g.:

return std::make_shared<mgm::BufferAllocator>(gbm.device, mgm::BypassOption::prohibited, false);

Compare the existing second (enum) to the new third (bool) option.

~~~~~~~~~

253 + return mir::Fd{IntOwnedFd{fd}};

We should dup() this fd to maintain the interface (i.e., that authenticated_fd() returns a new, independent fd). Ideally we would change the calling code to properly use mir::Fds, but that is beyond the scope of this MP.

~~~~~~~~~

333 + DRMHelper(bool const use_render_node)

Similarly, better to use an enum instead of a bool.

~~~~~~~~~

353 -mgm::IpcOperations::IpcOperations(std::shared_ptr<DRMAuthentication> const& drm_auth) :
355 +mgm::IpcOperations::IpcOperations(std::shared_ptr<DRMAuthentication> const& drm, bool const authenticate) :
...
364 + if (!authenticate)
365 + BOOST_THROW_EXCEPTION(
366 + std::runtime_error("Invalid platform operation"));

We should let the DRMAuthenticator succeed or fail here on its own, no need for changing the IpcOperations code at all. I think the proposed version of DRMHelper will fail in the right way (i.e., throw for auth_magic(), succeed for auth_fd()).

~~~~~~~~~

394 + if (!authenticate)
395 + {
396 + auto package = std::make_shared<mg::PlatformIPCPackage>();
397 + package->ipc_fds.push_back(dup(drm->authenticated_fd()));
398 + return package;
399 + }
400 + return std::make_shared<MesaPlatformIPCPackage>(drm->authenticated_fd());

The two paths are functionally equivalent except 1. the dup() in the first path and 2. the first path leaks fds. As suggested earlier, it's better to dup inside authenticated_fd(), and by doing so we wouldn't need to change the code here at all.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote : Posted in a previous version of this proposal

> Some high level first impressions:
>
> ~~~~~~~~~
>
> The automatic module detection doesn't work correctly. In case of a priority
> tie, the first module found (in filesystem order) is selected. If that module
> is mesa-kms then mesa-x11 can never be loaded unless forced with the platform-
> graphics-lib option. We need to change mesa-kms and/or mesa-x11 to report
> different priorities depending on the environment.

The obvious thing to do here would be to make mesa-kms try to claim drm master in probe(). That fails when running under X11 (or not running with root), and mesa-kms will fail if it can't claim master anyway.

Apart from what Alexandros has pointed out, I think it's likely that you should be handling md::FdEvent::error in your Dispatchable::dispatch(). I believe Xlib's default behaviour in that case is SIGABRT, which we could do better than :)

Revision history for this message
Chris Halse Rogers (raof) : Posted in a previous version of this proposal
review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

It looks like there is enough useful feedback without me looking any deeper.

review: Abstain
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

Thanks for the suggestions. Should all be fixed now.

review: Approve
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

> Thanks for the suggestions. Should all be fixed now.

- Except for the fd_events::error which I've yet to do.
- Also running "sudo bin/mir_demo_server --vt 3" from an xterm doesn't seem to be working. It errs out saying "unrecognized option 'vt'".

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote : Posted in a previous version of this proposal

> > Thanks for the suggestions. Should all be fixed now.
>
> - Except for the fd_events::error which I've yet to do.
> - Also running "sudo bin/mir_demo_server --vt 3" from an xterm doesn't seem to
> be working. It errs out saying "unrecognized option 'vt'".

Yeah. This is because the X server has claimed DRM master, and so the mesa-kms probe detects that it can't claim master and bails.

We've talked before about loading *all* the platform modules, presenting all their options, and then having platform-specific options imply the use of that platform. That would fix this.

As I don't try to run mir from X this doesn't bother me :)

Revision history for this message
Chris Halse Rogers (raof) wrote : Posted in a previous version of this proposal

Otherwise, apart from handling the md::FdEvent::error case, looks good.

Non-blocking nits:

233 +enum class DMABufExtension
234 +{
235 + use,
236 + do_not_use
237 +};

I think this would be clearer as
enum class BufferImportMethod
{
    gbm_native_pixmap,
    dma_buf
};

Or similar; it's more descriptive of what it selects, and allows us to extend the import method in an obvious way if we need to in future.

Nit:
941 + if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx))
942 + BOOST_THROW_EXCEPTION(std::logic_error("Cannot make current"));

It's not really a logic error, is it? I'd expect this to be a runtime_error. For bonus marks, I guess, it could be an EGLError : public std::runtime_error and automatically slurp up the value of eglGetError().

1970 +extern "C" mg::PlatformPriority probe_graphics_platform()
1971 +{
1972 + auto dpy = XOpenDisplay(NULL);
1973 + if (dpy)
1974 + {
1975 + XCloseDisplay(dpy);
1976 +
1977 + auto udev = std::make_shared<mir::udev::Context>();
1978 + auto drm = std::make_shared<mgmh::DRMHelper>(mgmh::DRMNodeToUse::card_node);
1979 +
1980 + try {
1981 + drm->setup(udev);
1982 + drm->set_master();
1983 + }
1984 + catch(...)
1985 + {
1986 + return mg::PlatformPriority::best;
1987 + }
1988 +
1989 + drm->drop_master();
1990 + }
1991 + return mg::PlatformPriority::unsupported;
1992 +}

This is fine. It'd also be correct to return mg::PlatformPriority::supported if you can open the display and find a rendernode, without probing for being able to acquire master. (You might need to change the stub platforms to return PlatformPriority::unsupported+1 to make this work).

2809 +TEST_F(X11DisplayTest, creates_display_successfully)

I don't think this is testing anything useful, and is going to be one of those tests that we update every time we touch the relevant code. I'd prefer it if this test wasn't there.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

> 941 + if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx))
> 942 + BOOST_THROW_EXCEPTION(std::logic_error("Cannot make current"));

> It's not really a logic error, is it? I'd expect this to be a runtime_error.
> For bonus marks, I guess, it could be an EGLError : public std::runtime_error
> and automatically slurp up the value of eglGetError().

+1, but note we already have an egl_error we can use (see src/include/platform/mir/graphics/egl_error.h), that not only gets the eglGetError() value but knows how to print it properly. A few months ago we made an effort to move all EGL related exceptions to egl_error, so we could get more detailed information when something failed in the wild. I think it's worth using it in the X backend too.

2878 +// fake_devices.add_standard_device("standard-drm-devices");

Not needed.

2900 + try
2901 + {
2902 + auto platform = create_platform();
2903 + } catch(...)
2904 + {
2905 + return;
2906 + }
2907 +
2908 + FAIL() << "Expected an exception to be thrown.";

... and elsewhere.

GMock has a construct to express this:

EXPECT_THROW({ create_platform(); }, std::exception); // or use a more specific exception type if applicable

Nit:

635 + EGLint egl_major, egl_minor;
636 + EGLConfig config;
637 + EGLint num_configs;
638 + EGLint vid;
639 + Window root;
640 + XVisualInfo *visInfo, visTemplate;
641 + XSetWindowAttributes attr;
642 + int num_visuals;
643 + unsigned long mask;
644 + char const * const title = "Mir On X";

I guess this is based on some C code. In C++, it has proved easier to read to just declare each variable when it's created.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

partial review so far:

needs fixings:
indentation is a bit awry, some places have tabs
http://unity.ubuntu.com/mir/cppguide/index.html?showone=Spaces_vs._Tabs#Spaces_vs._Tabs

185 + int prime_fd;
Handling of this fd isn't exception-safe (eg, if l177 threw), using mir::Fd would help.

611 +mgx::Display::Display(::Display *dpy)
some of the resources in this constructor are also not exception safe. (eg, if eglCreateContext threw some of the resources (like win) might leak)

145-150 c-style casts
http://unity.ubuntu.com/mir/cppguide/index.html?showone=Casting#Casting

126 + if (buffer_import_method == mgm::BufferImportMethod::dma_buf)
Switching on this enum in the buffer type suggests to me that the mgm::Buffer should have two different implementations based on the mapping method, or that there's mgm::BufferImporter interface that mgm::Buffer should take, that abstracts the importation on behalf of the buffer.

needs info:
755 +void mgx::Display::register_configuration_change_handler(
756 + EventHandlerRegister& /* event_handler*/,
757 + DisplayConfigurationChangeHandler const& /*change_handler*/)
758 +{
759 +}
I'm not sure what would happen if the window backing the server changes size. (is this a possible thing for X to do?)

review: Needs Fixing
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

> 126 + if (buffer_import_method ==
> mgm::BufferImportMethod::dma_buf)
> Switching on this enum in the buffer type suggests to me that the mgm::Buffer
> should have two different implementations based on the mapping method, or that
> there's mgm::BufferImporter interface that mgm::Buffer should take, that
> abstracts the importation on behalf of the buffer.

I'm not sure I understand what needs to be done here. I've fixed the others.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

> > 126 + if (buffer_import_method ==
> > mgm::BufferImportMethod::dma_buf)
> > Switching on this enum in the buffer type suggests to me that the
> mgm::Buffer
> > should have two different implementations based on the mapping method, or
> that
> > there's mgm::BufferImporter interface that mgm::Buffer should take, that
> > abstracts the importation on behalf of the buffer.
>
>
> I'm not sure I understand what needs to be done here. I've fixed the others.

It seems like there's two implementations of mgm::BufferTextureBinder in one class in the MP. i.e., it seems more in accord with the existing design to have:

GBMNativeTextureBinder : public mgm::BufferTextureBinder
and
DMABufTextureBinder : public mgm::BufferTextureBinder

and then have mgm::BufferAllocator::alloc_hardware_buffer() create the mgm::Buffer with the right type of BufferTextureBinder

Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

Another round:

1977 + auto dpy = XOpenDisplay(NULL);
nullptr?

1907 +::Display *x_display = nullptr;
1908 +
1909 +mgx::Platform::Platform()
IIRC, we guard against opening a platform twice, but we should throw if platform is created twice if this really has to be a singleton. (in the current case, it would leak x_display)

I guess also, x_display should be an RAII type in case either of these throw:
1918 + drm->setup(udev);
1919 + gbm.setup(*drm);

1651 +extern ::Display *x_display;
1400 +extern ::Display *x_display;
These two classes should take this dependency explicitly (as a shared_ptr perhaps), as this guards against ~Platform() being destroyed and destroying the resources that the two classes need.

Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

931 + return {{0,0}, {width,height}};
could just be:
931 + return {{0,0}, size};

Is calling mgx::Display::configure() or the X window getting resized something that's not supported?

(similar question) should mgx::Display::pause()/resume() be hooked up somewhat like the VT's work, except of course, if the X server pauses.

1058 + mg::DisplayConfigurationOutputId{0},
0 is defined to be invalid (more detail: https://bugs.launchpad.net/mir/+bug/1463873)

1414 + auto ret = true
spacing

365 -struct MesaPlatformIPCPackage : public mg::PlatformIPCPackage
366 +struct DefaultPlatformIPCPackage : public mg::PlatformIPCPackage
"Default" doesn't seem to add much to the name, if it has to be renamed, maybe just PlatformIPCPackage?

Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

1189 +void mgx::DisplayGroup::post()
1190 +{
1191 +}

There's a bit of a functional difference if we don't do anything here (from mc::MultiThreadedCompositor's perspective). Android and mesa both actually post the content stored up in the DisplayBuffer in the post() function. Is it not possible to separate the swapping from the posting?

Revision history for this message
Robert Carr (robertcarr) wrote : Posted in a previous version of this proposal

Inclined to agree with kdub on extracting the buand ffer texture binder RAII for ::Display type.

+ win = XCreateWindow(x_dpy, root, 0, 0, 1280, 1024,

Should be the width/height members right?

+ event.key.modifiers = mir_input_event_modifier_none;

Needs impl or a TODO?

1703: unneeded

+ InputDeviceInfo info;

I can't find where this is initialized?

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

> > > 126 + if (buffer_import_method ==
> > > mgm::BufferImportMethod::dma_buf)
> > > Switching on this enum in the buffer type suggests to me that the
> > mgm::Buffer
> > > should have two different implementations based on the mapping method, or
> > that
> > > there's mgm::BufferImporter interface that mgm::Buffer should take, that
> > > abstracts the importation on behalf of the buffer.
> >
> >
> > I'm not sure I understand what needs to be done here. I've fixed the others.
>
> It seems like there's two implementations of mgm::BufferTextureBinder in one
> class in the MP. i.e., it seems more in accord with the existing design to
> have:
>
> GBMNativeTextureBinder : public mgm::BufferTextureBinder
> and
> DMABufTextureBinder : public mgm::BufferTextureBinder
>
> and then have mgm::BufferAllocator::alloc_hardware_buffer() create the
> mgm::Buffer with the right type of BufferTextureBinder

Done.

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

> Another round:
>
> 1977 + auto dpy = XOpenDisplay(NULL);
> nullptr?
>
> 1907 +::Display *x_display = nullptr;
> 1908 +
> 1909 +mgx::Platform::Platform()
> IIRC, we guard against opening a platform twice, but we should throw if
> platform is created twice if this really has to be a singleton. (in the
> current case, it would leak x_display)
>
> I guess also, x_display should be an RAII type in case either of these throw:
> 1918 + drm->setup(udev);
> 1919 + gbm.setup(*drm);
>
> 1651 +extern ::Display *x_display;
> 1400 +extern ::Display *x_display;
> These two classes should take this dependency explicitly (as a shared_ptr
> perhaps), as this guards against ~Platform() being destroyed and destroying
> the resources that the two classes need.

Done.

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

> Is calling mgx::Display::configure() or the X window getting resized something
> that's not supported?

I currently create an Xwindow that is not resizeable. This is a TODO.

>
> (similar question) should mgx::Display::pause()/resume() be hooked up somewhat
> like the VT's work, except of course, if the X server pauses.

I am not sure if there is a need for this. If there is it's another TODO.

Other issues now fixed.

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

> 1189 +void mgx::DisplayGroup::post()
> 1190 +{
> 1191 +}
>
> There's a bit of a functional difference if we don't do anything here (from
> mc::MultiThreadedCompositor's perspective). Android and mesa both actually
> post the content stored up in the DisplayBuffer in the post() function. Is it
> not possible to separate the swapping from the posting?

I don't see how. X is more like the offscreen or nested in this aspect where this function is null.

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

> Inclined to agree with kdub on extracting the buand ffer texture binder RAII
> for ::Display type.
>
> + win = XCreateWindow(x_dpy, root, 0, 0, 1280, 1024,
>
> Should be the width/height members right?
>
> + event.key.modifiers = mir_input_event_modifier_none;
>
> Needs impl or a TODO?

This is a TODO.

>
>
> 1703: unneeded
>
> + InputDeviceInfo info;
>
> I can't find where this is initialized?

Ah ok, now fixed.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote : Posted in a previous version of this proposal
Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

> > (similar question) should mgx::Display::pause()/resume() be hooked up
> somewhat
> > like the VT's work, except of course, if the X server pauses.
>
> I am not sure if there is a need for this. If there is it's another TODO.

We should probably throw then with a runtime not-supported exception. If a client of the x-backed server tried to configure via the client api, the request would be silently ignored.

Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

1414 +mix::XDispatchable::XDispatchable(int raw_fd)

This class has a 2 step initialization; it depends on sink as a dependency of the class, but its not in the constructor. Consider:

mix::XDispatchable dispatch(fd);
dispatch.dispatch(...)

The second call would not fulfill what it should be doing (in the case here, it would segfault; if we checked for sink before calling send(), then we would not accomplish the function)

It would be better to plumb through:
mix::XDispatchable dispatch(fd, sink);
so then dispatch.dispatch(...) would always work. We'd probably also refine the structure of the system, as we (probably) have to plumb the sink dependency a bit differently.

Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

> It would be better to plumb through:
> mix::XDispatchable dispatch(fd, sink);

actually, looking through again, it probably has to be:

mix::XDispatchable dispatch(fd, sink, x11_connection);

as that's another dependency of the class. Its not immediately obvious that dispatch() wouldn't work if the Platform class had not instantiated it.

Revision history for this message
Robert Carr (robertcarr) wrote : Posted in a previous version of this proposal

-- DRMNodeToUse::card_node/render_node

Should be

-- DRMNodeToUse::card/render

Revision history for this message
Robert Carr (robertcarr) wrote : Posted in a previous version of this proposal

--- src/platforms/mesa/server/x11/xserver_connection.h 1970-01-01 00:00:00 +0000

It's better to use an std::unique_ptr with a function deleter. You can use a C function pointer type as opposed to std::function and thus use XCloseDisplay directly and it will be zero overhead.

Otherwise a shared_ptr with a custom deleter is better than a custom type I think.

Revision history for this message
Robert Carr (robertcarr) wrote : Posted in a previous version of this proposal

Otherwise, as in if std::unique_ptr is somehow unsuitable

Revision history for this message
Robert Carr (robertcarr) wrote : Posted in a previous version of this proposal

What is the _wrapper for in + MOCK_METHOD10(XCreateWindow_wrapper, Window(Display*, Window, unsigned int, unsigned int, unsigned int, int, unsigned int, Visual*, unsigned long, XSetWindowAttributes*));

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

> 1414 +mix::XDispatchable::XDispatchable(int raw_fd)
>
> This class has a 2 step initialization; it depends on sink as a dependency of
> the class, but its not in the constructor. Consider:
>
> mix::XDispatchable dispatch(fd);
> dispatch.dispatch(...)
>
> The second call would not fulfill what it should be doing (in the case here,
> it would segfault; if we checked for sink before calling send(), then we would
> not accomplish the function)
>
> It would be better to plumb through:
> mix::XDispatchable dispatch(fd, sink);
> so then dispatch.dispatch(...) would always work. We'd probably also refine
> the structure of the system, as we (probably) have to plumb the sink
> dependency a bit differently.

This is due to mi::InputDevice having two distinct functions :

    std::shared_ptr<dispatch::Dispatchable> dispatchable() override;
    void start(input::InputSink* destination) override;

That is, before the InputDevice is started, dispatchable might be obtained and its dispatch() function might be called when there is no sink. In such a case it makes sense to just consume the event but ignore the dispatch which is what the code is doing. I didn't want to change this semantics (of being able to obtain and dispatch even when there is no sink attached) as I don't know what the repercussions would be. It wouldn't crash as the line "if (sink)" is protecting it.

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

> > It would be better to plumb through:
> > mix::XDispatchable dispatch(fd, sink);
>
> actually, looking through again, it probably has to be:
>
> mix::XDispatchable dispatch(fd, sink, x11_connection);
>
> as that's another dependency of the class. Its not immediately obvious that
> dispatch() wouldn't work if the Platform class had not instantiated it.

x11_connection is an (external) global. I'm going to have to think of something in the long-term but in the short-term we'll need to live with this ugliness. But at least things would fail miserably way before we'd get to this point.

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

> We should probably throw then with a runtime not-supported exception. If a
> client of the x-backed server tried to configure via the client api, the
> request would be silently ignored.

Fixed

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

> --- src/platforms/mesa/server/x11/xserver_connection.h 1970-01-01 00:00:00
> +0000
>
> It's better to use an std::unique_ptr with a function deleter. You can use a C
> function pointer type as opposed to std::function and thus use XCloseDisplay
> directly and it will be zero overhead.
>
> Otherwise a shared_ptr with a custom deleter is better than a custom type I
> think.

I don't think unique_ptr is appropriate as it's being shared between modules. And I'm not worried about the delete overhead - this will only happen when the server goes down, not on every frame or anything like that.

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

> What is the _wrapper for in + MOCK_METHOD10(XCreateWindow_wrapper,
> Window(Display*, Window, unsigned int, unsigned int, unsigned int, int,
> unsigned int, Visual*, unsigned long, XSetWindowAttributes*));

XCreateWindow takes more than 10 args but gmock accepts up to 10. The way to get around this is to drop some of the uninteresting args and limit the number to 10 with a wrapper. See the response to the original question in : https://code.google.com/p/googlemock/issues/detail?id=117

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

> -- DRMNodeToUse::card_node/render_node
>
> Should be
>
> -- DRMNodeToUse::card/render

Fixed

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

Reproposed using the new options branch.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

Nonblocking:
180 + std::runtime_error(msg)) << boost::errinfo_errno(errno));

std::system_error does this in a better-consumable way without the boost::enable_errinfo faffery.

234 + dynamic_cast<EGLImageBufferTextureBinder*>(new DMABufTextureBinder{bo, egl_extensions}) :
235 + dynamic_cast<EGLImageBufferTextureBinder*>(new NativePixmapTextureBinder{bo, egl_extensions})

What's the need for dynamic_cast here? Both DMABufTextureBinder and NativePixmapTextureBinder are statically known to be subclasses of EGLImageBufferTextureBinder.

763 + eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
764 + eglDestroyContext(egl_dpy, egl_ctx);
765 + eglDestroySurface(egl_dpy, egl_surf);

Funky indentation.

2880 +TEST_F(X11DisplayTest, creates_display_successfully)

I continue to think that this test doesn't test anything valuable, and should be removed.

Otherwise seems sane.

review: Approve
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

186 +

Not sure this empty line improves readability.

~~~~~~~~~~~~~~~~~~~~~

234 + dynamic_cast<EGLImageBufferTextureBinder*>(new DMABufTextureBinder{bo, egl_extensions}) :

What Chris said, and also we can use make_unique.

~~~~~~~~~~~~~~~~~~~~~

723 + eglTerminate(egl_dpy);
724 + XDestroyWindow(x_dpy, win);

731 + eglDestroyContext(egl_dpy, egl_ctx);
732 + eglTerminate(egl_dpy);
733 + XDestroyWindow(x_dpy, win);

750 + XFree(visInfo);

Using RAII wrappers for these types would help us avoid explicit destruction and potential memory leaks (e.g., as things are now we may leak visInfo).

~~~~~~~~~~~~~~~~~~~~~

1467 + std::chrono::time_point<std::chrono::system_clock> tp;

1549 + ~XDispatchable() = default;
1550 +
1551 + XDispatchable(XDispatchable const&) = delete;
1552 + XDispatchable& operator=(XDispatchable const&) = delete;

No need for explicit default (omitting the destructor creates a default one), or delete (methods are deleted in parent interface class).

~~~~~~~~~~~~~~~~~~~~~

1925 +std::shared_ptr<mx::X11Connection> x11_connection;

It would be better to avoid having static variables hold resources if we can help it. In this case, we could make the x11_connection a member variable of platform, and, if we *really* need to guard against multiple instantiations (which we are not doing in any other platform, btw), we could use a static (atomic) bool variable.

~~~~~~~~~~~~~~~~~~~~~

2469 +// Window XCreateWindow(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, int depth, unsigned int class, Visual *visual, unsigned long valuemask, XSetWindowAttributes *attributes)

Unnecessary comment.

~~~~~~~~~~~~~~~~~~~~~

2461 + return global_mock->XGetVisualInfo(display, vinfo_mask, vinfo_template, nitems_return);

3088 + X11DispatchableTest()
3089 + {
3090 + }

... and at various other places.

A few instances of tabs instead of spaces. Please grep the diff for tabs and replace them.

review: Needs Fixing
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

1467 + std::chrono::time_point<std::chrono::system_clock> tp;

Is the system_clock the right clock to use? I would expect a monotonic/steady clock, like our android-based input system uses.

review: Needs Fixing
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

> 1467 + std::chrono::time_point<std::chrono::system_clock> tp;
>
> Is the system_clock the right clock to use? I would expect a monotonic/steady clock,
> like our android-based input system uses.

A scratch this, we are not measuring time with the clock, just converting units.

Revision history for this message
Robert Carr (robertcarr) wrote :

732 + eglTerminate(egl_dpy);
733 + XDestroyWindow(x_dpy, win);

+ other places in this ctor

are strong evidence EGLDisplay and the XWindow should be an RAII type.

Revision history for this message
Robert Carr (robertcarr) wrote :

Lots of indentaiton errors but otherwise seems ok to me :D

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

I try running:

$ bin/mir_demo_server --test-client bin/mir_demo_client_egltriangle

And see a window containing a titlebar. But no triangle.

Is this expected?

review: Needs Information
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Also:

$ bin/mir_demo_standalone_render_surfaces

Gives a blank window.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> I try running:
>
> $ bin/mir_demo_server --test-client bin/mir_demo_client_egltriangle
>
> And see a window containing a titlebar. But no triangle.
>
> Is this expected?

Apparently so - I've got an intel GPU and there are driver issues with EGL clients.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

$ bin/mir_demo_server --platform-input-lib lib/server-modules/server-mesa-x11.so.3 --test-client bin/mir_demo_client_multiwin

This draws OK, but e.g. Shift+F11/Ctrl+F11 do not toggle the surface vertical/horizontal maximize. (And Alt+F4, Ctrl+F4 are intercepted before hitting the server.)

What's the expectation?

review: Needs Information
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

212 +template<typename T,typename V>
213 +T up_cast(V x) {
214 + return x;
215 +}
216 +
...
239 + // To see why up_cast is needed, see
240 + // http://stackoverflow.com/questions/6179314/casting-pointers-and-the-ternary-operator-have-i-reinvented-the-wheel
241 std::unique_ptr<EGLImageBufferTextureBinder> texture_binder{
242 - new EGLImageBufferTextureBinder{bo, egl_extensions}};
243 + buffer_import_method == mgm::BufferImportMethod::dma_buf ?
244 + up_cast<EGLImageBufferTextureBinder*>(new DMABufTextureBinder{bo, egl_extensions}) :
245 + up_cast<EGLImageBufferTextureBinder*>(new NativePixmapTextureBinder{bo, egl_extensions})};

Personally, I wouldn't write an up_cast<> template for this (people will need to look at the definition to follow the code). Instead:

auto make_texture_binder(
    BufferImportMethod const buffer_import_method,
    std::shared_ptr<gbm_bo> const& gbm_bo,
    std::shared_ptr<mg::EGLExtensions> const& egl_extensions)
=> std::unique_ptr<EGLImageBufferTextureBinder>
{
    if (buffer_import_method == mgm::BufferImportMethod::dma_buf)
        return std::make_unique<DMABufTextureBinder>(bo, egl_extensions);
    else
        return std::make_unique<NativePixmapTextureBinder>(bo, egl_extensions);
}

...

    auto const buffer =
        std::make_shared<GBMBuffer>(bo, bo_flags, make_texture_binder(buffer_import_method, gbm_bo, egl_extensions));

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Just nits so far. (May well be more if I re-read the code later.)

127 +

Neededless whitespace

~~~~

485 +namespace mgmh = mgm::helpers;

unused.

~~~~

511 -

Helpful whitespace

review: Needs Fixing
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

> $ bin/mir_demo_server --platform-input-lib lib/server-modules/server-
> mesa-x11.so.3 --test-client bin/mir_demo_client_multiwin
>
> This draws OK, but e.g. Shift+F11/Ctrl+F11 do not toggle the surface
> vertical/horizontal maximize. (And Alt+F4, Ctrl+F4 are intercepted before
> hitting the server.)
>
> What's the expectation?

Meta keys are not handled yet.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

I have addressed all the reviews so far with the exception of the following :

alf - static variables hold resources
1925 +std::shared_ptr<mx::X11Connection> x11_connection;

The problem here is that our graphics and input platforms do not share any context and this is a TODO. I'd rather not spend any more time on what amounts to a bandaid solution.
-----------------------------------------------------------------------------------

chris - this test doesn't test anything valuable, and should be removed.
2880 +TEST_F(X11DisplayTest, creates_display_successfully)

This test is pretty similar on other platforms. I'd like to keep it so I can refine it.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Looks good.

review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

I'd rather have this code on trunk than wait for known gaps to be filled (EGL clients, missing meta key input and mouse input).

review: Approve
Revision history for this message
Kevin DuBois (kdub) wrote :

> I have addressed all the reviews so far with the exception of the following :
>
> alf - static variables hold resources
> 1925 +std::shared_ptr<mx::X11Connection> x11_connection;
>
> The problem here is that our graphics and input platforms do not share any
> context and this is a TODO. I'd rather not spend any more time on what amounts
> to a bandaid solution.

The issue though is that its a non-explicit (ie, not in the destructor) dependency of the classes that use it, which makes the classes that use it a bit trickier. +1 in the name of not spending more time, but would be better with a TODO comment, I think.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

Thanks for this work, I'm waiting for this since some time, as it will help a lot the development.

As per inline comment, I guess symbols should be updated to platform 4.

Also, I think that a new mir-platform-graphics-mesa-x114 package should be generated.

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

> Thanks for this work, I'm waiting for this since some time, as it will help a
> lot the development.
>
> As per inline comment, I guess symbols should be updated to platform 4.
>
> Also, I think that a new mir-platform-graphics-mesa-x114 package should be
> generated.

Thanks for noticing this. Fixed now.

We don't yet have a package for this. X11 support is still pretty raw. Getting the minimally acceptable code to the trunk is the first priority, which is not necessarily equivalent to having a minimally functional x11 platform support.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

> We don't yet have a package for this. X11 support is still pretty raw.

Ok, thanks, fair enough.

Probably, one thing to add is to grab the mouse input (and hide the X cursor) when the Mir on X window is focused, or it will be hard to interact without disturbing the environment :), but things seem to start working pretty well (also launching it in a wily LXC container on a trusty host with 3.19 [vivid lts] kernel).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-07-16 07:03:19 +0000
3+++ CMakeLists.txt 2015-07-22 20:26:39 +0000
4@@ -144,10 +144,10 @@
5 # Default to KMS backend, but build all of them
6 set(
7 MIR_PLATFORM
8- mesa-kms;android
9+ mesa-kms;android;mesa-x11
10 CACHE
11 STRING
12- "a list of graphics backends to build (options are 'mesa-kms' or 'android')"
13+ "a list of graphics backends to build (options are 'mesa-kms', 'android' or 'mesa-x11')"
14 )
15
16 list(GET MIR_PLATFORM 0 MIR_TEST_PLATFORM)
17@@ -159,6 +159,9 @@
18 if (platform STREQUAL "android")
19 set(MIR_BUILD_PLATFORM_ANDROID TRUE)
20 endif()
21+ if (platform STREQUAL "mesa-x11")
22+ set(MIR_BUILD_PLATFORM_MESA_X11 TRUE)
23+ endif()
24 endforeach(platform)
25
26 find_package(EGL REQUIRED)
27@@ -182,7 +185,7 @@
28 find_package(LibHardware REQUIRED)
29 endif()
30
31-if (MIR_BUILD_PLATFORM_MESA_KMS)
32+if (MIR_BUILD_PLATFORM_MESA_KMS OR MIR_BUILD_PLATFORM_MESA_X11)
33 find_package( PkgConfig )
34 pkg_check_modules( GBM REQUIRED gbm>=9.0.0)
35 pkg_check_modules( DRM REQUIRED libdrm )
36
37=== modified file 'src/platforms/CMakeLists.txt'
38--- src/platforms/CMakeLists.txt 2015-07-21 07:09:45 +0000
39+++ src/platforms/CMakeLists.txt 2015-07-22 20:26:39 +0000
40@@ -52,8 +52,8 @@
41
42 add_subdirectory(common/)
43
44-if (MIR_BUILD_PLATFORM_MESA_KMS)
45- add_subdirectory(mesa/)
46+if (MIR_BUILD_PLATFORM_MESA_KMS OR MIR_BUILD_PLATFORM_MESA_X11)
47+ add_subdirectory(mesa/)
48 endif()
49
50 if (MIR_BUILD_PLATFORM_ANDROID)
51
52=== modified file 'src/platforms/mesa/server/CMakeLists.txt'
53--- src/platforms/mesa/server/CMakeLists.txt 2015-06-05 06:28:36 +0000
54+++ src/platforms/mesa/server/CMakeLists.txt 2015-07-22 20:26:39 +0000
55@@ -3,3 +3,6 @@
56 if (MIR_BUILD_PLATFORM_MESA_KMS)
57 add_subdirectory(kms/)
58 endif()
59+if (MIR_BUILD_PLATFORM_MESA_X11)
60+ add_subdirectory(x11/)
61+endif()
62
63=== modified file 'src/platforms/mesa/server/common/buffer_allocator.cpp'
64--- src/platforms/mesa/server/common/buffer_allocator.cpp 2015-07-17 22:51:35 +0000
65+++ src/platforms/mesa/server/common/buffer_allocator.cpp 2015-07-22 20:26:39 +0000
66@@ -22,10 +22,12 @@
67 #include "buffer_texture_binder.h"
68 #include "anonymous_shm_file.h"
69 #include "shm_buffer.h"
70+#include "display_helpers.h"
71 #include "mir/graphics/egl_extensions.h"
72 #include "mir/graphics/egl_error.h"
73 #include "mir/graphics/buffer_properties.h"
74 #include <boost/throw_exception.hpp>
75+#include <boost/exception/errinfo_errno.hpp>
76
77 #include <EGL/egl.h>
78 #include <EGL/eglext.h>
79@@ -37,6 +39,7 @@
80 #include <system_error>
81 #include <gbm.h>
82 #include <cassert>
83+#include <fcntl.h>
84
85 namespace mg = mir::graphics;
86 namespace mgm = mg::mesa;
87@@ -50,7 +53,9 @@
88 public:
89 EGLImageBufferTextureBinder(std::shared_ptr<gbm_bo> const& gbm_bo,
90 std::shared_ptr<mg::EGLExtensions> const& egl_extensions)
91- : bo{gbm_bo}, egl_extensions{egl_extensions}, egl_image{EGL_NO_IMAGE_KHR}
92+ : bo{gbm_bo},
93+ egl_extensions{egl_extensions},
94+ egl_image{EGL_NO_IMAGE_KHR}
95 {
96 }
97
98@@ -68,6 +73,24 @@
99 egl_extensions->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image);
100 }
101
102+protected:
103+ virtual void ensure_egl_image() = 0;
104+
105+ std::shared_ptr<gbm_bo> const bo;
106+ std::shared_ptr<mg::EGLExtensions> const egl_extensions;
107+ EGLDisplay egl_display;
108+ EGLImageKHR egl_image;
109+};
110+
111+class NativePixmapTextureBinder : public EGLImageBufferTextureBinder
112+{
113+public:
114+ NativePixmapTextureBinder(std::shared_ptr<gbm_bo> const& gbm_bo,
115+ std::shared_ptr<mg::EGLExtensions> const& egl_extensions)
116+ : EGLImageBufferTextureBinder(gbm_bo, egl_extensions)
117+ {
118+ }
119+
120 private:
121 void ensure_egl_image()
122 {
123@@ -82,19 +105,71 @@
124 EGL_NONE
125 };
126
127- egl_image = egl_extensions->eglCreateImageKHR(egl_display, EGL_NO_CONTEXT,
128+ egl_image = egl_extensions->eglCreateImageKHR(egl_display,
129+ EGL_NO_CONTEXT,
130 EGL_NATIVE_PIXMAP_KHR,
131 reinterpret_cast<void*>(bo_raw),
132 image_attrs);
133 if (egl_image == EGL_NO_IMAGE_KHR)
134- BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGLImage from GBM bo"));
135- }
136- }
137-
138- std::shared_ptr<gbm_bo> const bo;
139- std::shared_ptr<mg::EGLExtensions> const egl_extensions;
140- EGLDisplay egl_display;
141- EGLImageKHR egl_image;
142+ BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGLImage"));
143+ }
144+ }
145+};
146+
147+class DMABufTextureBinder : public EGLImageBufferTextureBinder
148+{
149+public:
150+ DMABufTextureBinder(std::shared_ptr<gbm_bo> const& gbm_bo,
151+ std::shared_ptr<mg::EGLExtensions> const& egl_extensions)
152+ : EGLImageBufferTextureBinder(gbm_bo, egl_extensions)
153+ {
154+ }
155+
156+private:
157+ void ensure_egl_image()
158+ {
159+ if (egl_image == EGL_NO_IMAGE_KHR)
160+ {
161+ egl_display = eglGetCurrentDisplay();
162+ gbm_bo* bo_raw{bo.get()};
163+
164+ auto device = gbm_bo_get_device(bo_raw);
165+ auto gem_handle = gbm_bo_get_handle(bo_raw).u32;
166+ auto drm_fd = gbm_device_get_fd(device);
167+ int raw_fd = -1;
168+
169+ auto ret = drmPrimeHandleToFD(drm_fd, gem_handle, DRM_CLOEXEC, &raw_fd);
170+ prime_fd = mir::Fd{raw_fd};
171+ if (ret)
172+ {
173+ std::string const msg("Failed to get PRIME fd from gbm bo");
174+ BOOST_THROW_EXCEPTION(
175+ std::system_error(errno, std::system_category(), "Failed to get PRIME fd from gbm bo"));
176+ }
177+
178+ const EGLint image_attrs_X[] =
179+ {
180+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
181+ EGL_WIDTH, static_cast<const EGLint>(gbm_bo_get_width(bo_raw)),
182+ EGL_HEIGHT, static_cast<const EGLint>(gbm_bo_get_height(bo_raw)),
183+ EGL_LINUX_DRM_FOURCC_EXT, static_cast<const EGLint>(gbm_bo_get_format(bo_raw)),
184+ EGL_DMA_BUF_PLANE0_FD_EXT, prime_fd,
185+ EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
186+ EGL_DMA_BUF_PLANE0_PITCH_EXT, static_cast<const EGLint>(gbm_bo_get_stride(bo_raw)),
187+ EGL_NONE
188+ };
189+
190+ egl_image = egl_extensions->eglCreateImageKHR(egl_display,
191+ EGL_NO_CONTEXT,
192+ EGL_LINUX_DMA_BUF_EXT,
193+ static_cast<EGLClientBuffer>(nullptr),
194+ image_attrs_X);
195+ if (egl_image == EGL_NO_IMAGE_KHR)
196+ BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGLImage"));
197+ }
198+ }
199+
200+ mir::Fd prime_fd;
201 };
202
203 struct GBMBODeleter
204@@ -106,15 +181,30 @@
205 }
206 };
207
208+auto make_texture_binder(
209+ mgm::BufferImportMethod const buffer_import_method,
210+ std::shared_ptr<gbm_bo> const& bo,
211+ std::shared_ptr<mg::EGLExtensions> const& egl_extensions)
212+-> std::unique_ptr<EGLImageBufferTextureBinder>
213+{
214+ if (buffer_import_method == mgm::BufferImportMethod::dma_buf)
215+ return std::make_unique<DMABufTextureBinder>(bo, egl_extensions);
216+ else
217+ return std::make_unique<NativePixmapTextureBinder>(bo, egl_extensions);
218+}
219+
220 }
221
222 mgm::BufferAllocator::BufferAllocator(
223 gbm_device* device,
224- BypassOption bypass_option)
225+ BypassOption bypass_option,
226+ mgm::BufferImportMethod const buffer_import_method)
227 : device(device),
228 egl_extensions(std::make_shared<mg::EGLExtensions>()),
229- bypass_option(bypass_option)
230-
231+ bypass_option(buffer_import_method == mgm::BufferImportMethod::dma_buf ?
232+ mgm::BypassOption::prohibited :
233+ bypass_option),
234+ buffer_import_method(buffer_import_method)
235 {
236 }
237
238@@ -169,12 +259,9 @@
239
240 std::shared_ptr<gbm_bo> bo{bo_raw, GBMBODeleter()};
241
242- std::unique_ptr<EGLImageBufferTextureBinder> texture_binder{
243- new EGLImageBufferTextureBinder{bo, egl_extensions}};
244-
245 /* Create the GBMBuffer */
246 auto const buffer =
247- std::make_shared<GBMBuffer>(bo, bo_flags, std::move(texture_binder));
248+ std::make_shared<GBMBuffer>(bo, bo_flags, make_texture_binder(buffer_import_method, bo, egl_extensions));
249
250 return buffer;
251 }
252@@ -257,5 +344,5 @@
253 return std::make_unique<mgm::GBMBuffer>(
254 bo,
255 package->flags,
256- std::make_unique<EGLImageBufferTextureBinder>(bo, egl_extensions));
257+ std::make_unique<NativePixmapTextureBinder>(bo, egl_extensions));
258 }
259
260=== modified file 'src/platforms/mesa/server/common/buffer_allocator.h'
261--- src/platforms/mesa/server/common/buffer_allocator.h 2015-07-16 07:03:19 +0000
262+++ src/platforms/mesa/server/common/buffer_allocator.h 2015-07-22 20:26:39 +0000
263@@ -38,10 +38,17 @@
264
265 namespace mesa
266 {
267+
268+enum class BufferImportMethod
269+{
270+ gbm_native_pixmap,
271+ dma_buf
272+};
273+
274 class BufferAllocator: public graphics::GraphicBufferAllocator
275 {
276 public:
277- BufferAllocator(gbm_device* device, BypassOption bypass_option);
278+ BufferAllocator(gbm_device* device, BypassOption bypass_option, BufferImportMethod const buffer_import_method);
279
280 virtual std::shared_ptr<Buffer> alloc_buffer(
281 graphics::BufferProperties const& buffer_properties);
282@@ -60,6 +67,7 @@
283 std::shared_ptr<EGLExtensions> const egl_extensions;
284
285 BypassOption const bypass_option;
286+ BufferImportMethod const buffer_import_method;
287 };
288
289 }
290
291=== modified file 'src/platforms/mesa/server/common/display_helpers.cpp'
292--- src/platforms/mesa/server/common/display_helpers.cpp 2015-06-17 05:20:42 +0000
293+++ src/platforms/mesa/server/common/display_helpers.cpp 2015-07-22 20:26:39 +0000
294@@ -56,6 +56,9 @@
295 std::runtime_error(
296 "Tried to get authenticated DRM fd before setting up the DRM master"));
297
298+ if (node_to_use == DRMNodeToUse::render)
299+ return mir::Fd{IntOwnedFd{dup(fd)}};
300+
301 char* busid = drmGetBusid(fd);
302 if (!busid)
303 BOOST_THROW_EXCEPTION(
304@@ -199,13 +202,16 @@
305
306 mir::udev::Enumerator devices(udev);
307 devices.match_subsystem("drm");
308- devices.match_sysname("card[0-9]*");
309+ if (node_to_use == DRMNodeToUse::render)
310+ devices.match_sysname("renderD[0-9]*");
311+ else
312+ devices.match_sysname("card[0-9]*");
313
314 devices.scan_devices();
315
316 for(auto& device : devices)
317 {
318- if ((error = is_appropriate_device(udev, device)))
319+ if ((node_to_use == DRMNodeToUse::card) && (error = is_appropriate_device(udev, device)))
320 continue;
321
322 // If directly opening the DRM device is good enough for X it's good enough for us!
323@@ -216,26 +222,31 @@
324 continue;
325 }
326
327- // Check that the drm device is usable by setting the interface version we use (1.4)
328- drmSetVersion sv;
329- sv.drm_di_major = 1;
330- sv.drm_di_minor = 4;
331- sv.drm_dd_major = -1; /* Don't care */
332- sv.drm_dd_minor = -1; /* Don't care */
333-
334- if ((error = -drmSetInterfaceVersion(tmp_fd, &sv)))
335+ if (node_to_use == DRMNodeToUse::card)
336 {
337+ // Check that the drm device is usable by setting the interface version we use (1.4)
338+ drmSetVersion sv;
339+ sv.drm_di_major = 1;
340+ sv.drm_di_minor = 4;
341+ sv.drm_dd_major = -1; /* Don't care */
342+ sv.drm_dd_minor = -1; /* Don't care */
343+
344+ if ((error = -drmSetInterfaceVersion(tmp_fd, &sv)))
345+ {
346+ close(tmp_fd);
347+ tmp_fd = -1;
348+ continue;
349+ }
350+
351+ // Stop if this device has connections to display on
352+ if (count_connections(tmp_fd) > 0)
353+ break;
354+
355 close(tmp_fd);
356 tmp_fd = -1;
357- continue;
358 }
359-
360- // Stop if this device has connections to display on
361- if (count_connections(tmp_fd) > 0)
362+ else
363 break;
364-
365- close(tmp_fd);
366- tmp_fd = -1;
367 }
368
369 if (tmp_fd < 0)
370
371=== modified file 'src/platforms/mesa/server/common/display_helpers.h'
372--- src/platforms/mesa/server/common/display_helpers.h 2015-06-17 05:20:42 +0000
373+++ src/platforms/mesa/server/common/display_helpers.h 2015-07-22 20:26:39 +0000
374@@ -48,10 +48,16 @@
375 namespace helpers
376 {
377
378+enum class DRMNodeToUse
379+{
380+ render,
381+ card
382+};
383+
384 class DRMHelper : public DRMAuthentication
385 {
386 public:
387- DRMHelper() : fd{-1} {}
388+ DRMHelper(DRMNodeToUse const node_to_use) : fd{-1}, node_to_use{node_to_use} {}
389 ~DRMHelper();
390
391 DRMHelper(const DRMHelper &) = delete;
392@@ -65,6 +71,7 @@
393 void set_master() const;
394
395 int fd;
396+ DRMNodeToUse const node_to_use;
397
398 private:
399 // TODO: This herustic is temporary; should be replaced with
400
401=== modified file 'src/platforms/mesa/server/common/ipc_operations.cpp'
402--- src/platforms/mesa/server/common/ipc_operations.cpp 2015-06-17 05:20:42 +0000
403+++ src/platforms/mesa/server/common/ipc_operations.cpp 2015-07-22 20:26:39 +0000
404@@ -53,8 +53,7 @@
405 };
406 }
407
408-mgm::IpcOperations::IpcOperations(std::shared_ptr<DRMAuthentication> const& drm_auth) :
409- drm_auth{drm_auth}
410+mgm::IpcOperations::IpcOperations(std::shared_ptr<DRMAuthentication> const& drm) : drm{drm}
411 {
412 }
413
414@@ -103,7 +102,7 @@
415
416 try
417 {
418- drm_auth->auth_magic(auth_magic_request.magic);
419+ drm->auth_magic(auth_magic_request.magic);
420 auth_magic_response.status = 0;
421 }
422 catch (std::exception const& e)
423@@ -129,7 +128,7 @@
424 std::runtime_error("Invalid request message for auth_fd platform operation"));
425 }
426
427- return mg::PlatformOperationMessage{{},{drm_auth->authenticated_fd()}};
428+ return mg::PlatformOperationMessage{{},{drm->authenticated_fd()}};
429 }
430 else
431 {
432@@ -140,5 +139,5 @@
433
434 std::shared_ptr<mg::PlatformIPCPackage> mgm::IpcOperations::connection_ipc_package()
435 {
436- return std::make_shared<MesaPlatformIPCPackage>(drm_auth->authenticated_fd());
437+ return std::make_shared<MesaPlatformIPCPackage>(drm->authenticated_fd());
438 }
439
440=== modified file 'src/platforms/mesa/server/common/ipc_operations.h'
441--- src/platforms/mesa/server/common/ipc_operations.h 2015-06-17 05:20:42 +0000
442+++ src/platforms/mesa/server/common/ipc_operations.h 2015-07-22 20:26:39 +0000
443@@ -31,7 +31,7 @@
444 class IpcOperations : public PlatformIpcOperations
445 {
446 public:
447- IpcOperations(std::shared_ptr<DRMAuthentication> const&);
448+ IpcOperations(std::shared_ptr<DRMAuthentication> const& drm);
449
450 void pack_buffer(BufferIpcMessage& message, Buffer const& buffer, BufferIpcMsgType msg_type) const override;
451 void unpack_buffer(BufferIpcMessage& message, Buffer const& buffer) const override;
452@@ -40,7 +40,7 @@
453 unsigned int const opcode,
454 PlatformOperationMessage const& message) override;
455 private:
456- std::shared_ptr<DRMAuthentication> const drm_auth;
457+ std::shared_ptr<DRMAuthentication> const drm;
458 };
459
460 }
461
462=== modified file 'src/platforms/mesa/server/kms/guest_platform.cpp'
463--- src/platforms/mesa/server/kms/guest_platform.cpp 2015-07-16 07:03:19 +0000
464+++ src/platforms/mesa/server/kms/guest_platform.cpp 2015-07-22 20:26:39 +0000
465@@ -80,12 +80,12 @@
466 gbm.setup(fds.at(0));
467 set_guest_gbm_device(*nested_context, gbm.device);
468 ipc_ops = std::make_shared<mgm::IpcOperations>(
469- std::make_shared<mgm::NestedAuthentication>(nested_context));
470+ std::make_shared<mgm::NestedAuthentication>(nested_context));
471 }
472
473 std::shared_ptr<mg::GraphicBufferAllocator> mgm::GuestPlatform::create_buffer_allocator()
474 {
475- return std::make_shared<mgm::BufferAllocator>(gbm.device, mgm::BypassOption::prohibited);
476+ return std::make_shared<mgm::BufferAllocator>(gbm.device, mgm::BypassOption::prohibited, mgm::BufferImportMethod::gbm_native_pixmap);
477 }
478
479 std::shared_ptr<mg::Platform> create_guest_platform(
480
481=== modified file 'src/platforms/mesa/server/kms/platform.cpp'
482--- src/platforms/mesa/server/kms/platform.cpp 2015-07-17 17:23:11 +0000
483+++ src/platforms/mesa/server/kms/platform.cpp 2015-07-22 20:26:39 +0000
484@@ -39,6 +39,7 @@
485
486 namespace mg = mir::graphics;
487 namespace mgm = mg::mesa;
488+namespace mgmh = mgm::helpers;
489 namespace mo = mir::options;
490
491 namespace
492@@ -128,7 +129,7 @@
493 EmergencyCleanupRegistry& emergency_cleanup_registry,
494 BypassOption bypass_option)
495 : udev{std::make_shared<mir::udev::Context>()},
496- drm{std::make_shared<helpers::DRMHelper>()},
497+ drm{std::make_shared<mgmh::DRMHelper>(mgmh::DRMNodeToUse::card)},
498 listener{listener},
499 vt{vt},
500 bypass_option_{bypass_option}
501@@ -137,7 +138,7 @@
502 gbm.setup(*drm);
503
504 std::weak_ptr<VirtualTerminal> weak_vt = vt;
505- std::weak_ptr<helpers::DRMHelper> weak_drm = drm;
506+ std::weak_ptr<mgmh::DRMHelper> weak_drm = drm;
507 emergency_cleanup_registry.add(
508 [weak_vt,weak_drm]
509 {
510@@ -151,7 +152,7 @@
511
512 std::shared_ptr<mg::GraphicBufferAllocator> mgm::Platform::create_buffer_allocator()
513 {
514- return std::make_shared<mgm::BufferAllocator>(gbm.device, bypass_option_);
515+ return std::make_shared<mgm::BufferAllocator>(gbm.device, bypass_option_, mgm::BufferImportMethod::gbm_native_pixmap);
516 }
517
518 std::shared_ptr<mg::Display> mgm::Platform::create_display(
519@@ -184,7 +185,7 @@
520 std::shared_ptr<mg::Platform> create_host_platform(
521 std::shared_ptr<mo::Option> const& options,
522 std::shared_ptr<mir::EmergencyCleanupRegistry> const& emergency_cleanup_registry,
523- std::shared_ptr<mir::graphics::DisplayReport> const& report)
524+ std::shared_ptr<mg::DisplayReport> const& report)
525 {
526 auto real_fops = std::make_shared<RealVTFileOperations>();
527 auto real_pops = std::unique_ptr<RealPosixProcessOperations>(new RealPosixProcessOperations{});
528
529=== added directory 'src/platforms/mesa/server/x11'
530=== added file 'src/platforms/mesa/server/x11/CMakeLists.txt'
531--- src/platforms/mesa/server/x11/CMakeLists.txt 1970-01-01 00:00:00 +0000
532+++ src/platforms/mesa/server/x11/CMakeLists.txt 2015-07-22 20:26:39 +0000
533@@ -0,0 +1,61 @@
534+include_directories(
535+ ${server_common_include_dirs}
536+ ${PROJECT_SOURCE_DIR}/include/platform
537+ ${PROJECT_SOURCE_DIR}/include/client
538+ ${PROJECT_SOURCE_DIR}/src/platforms/mesa/server/common
539+)
540+
541+include_directories(
542+ ${DRM_INCLUDE_DIRS}
543+ ${GBM_INCLUDE_DIRS}
544+ ${EGL_INCLUDE_DIRS}
545+ ${GLESv2_INCLUDE_DIRS}
546+ ${UDEV_INCLUDE_DIRS}
547+)
548+
549+add_library(
550+ mirplatformservermesax11objects OBJECT
551+
552+ platform.cpp
553+ display.cpp
554+ display_configuration.cpp
555+ gl_context.cpp
556+ display_group.cpp
557+ display_buffer.cpp
558+ input/input.cpp
559+ input/input_platform.cpp
560+ input/input_device.cpp
561+ input/dispatchable.cpp
562+)
563+
564+add_library(
565+ mirplatformservermesax11 MODULE
566+
567+ $<TARGET_OBJECTS:mirplatformservermesax11objects>
568+)
569+
570+target_link_libraries(
571+ mirplatformservermesax11
572+ PRIVATE
573+ mirplatform
574+ EGL
575+ GLESv2
576+ X11
577+ mirsharedmesaservercommon-static
578+ ${Boost_PROGRAM_OPTIONS_LIBRARY}
579+ ${DRM_LDFLAGS} ${DRM_LIBRARIES}
580+ ${GBM_LDFLAGS} ${GBM_LIBRARIES}
581+)
582+
583+set(symbol_map ${CMAKE_CURRENT_SOURCE_DIR}/symbols.map)
584+
585+set_target_properties(
586+ mirplatformservermesax11 PROPERTIES
587+ OUTPUT_NAME server-mesa-x11
588+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/server-modules
589+ PREFIX ""
590+ SUFFIX ".so.${MIR_SERVER_GRAPHICS_PLATFORM_ABI}"
591+ LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${symbol_map}"
592+)
593+
594+install(TARGETS mirplatformservermesax11 LIBRARY DESTINATION ${MIR_SERVER_PLATFORM_PATH})
595
596=== added file 'src/platforms/mesa/server/x11/display.cpp'
597--- src/platforms/mesa/server/x11/display.cpp 1970-01-01 00:00:00 +0000
598+++ src/platforms/mesa/server/x11/display.cpp 2015-07-22 20:26:39 +0000
599@@ -0,0 +1,274 @@
600+/*
601+ * Copyright © 2015 Canonical Ltd.
602+ *
603+ * This program is free software: you can redistribute it and/or modify it
604+ * under the terms of the GNU Lesser General Public License version 3,
605+ * as published by the Free Software Foundation.
606+ *
607+ * This program is distributed in the hope that it will be useful,
608+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
609+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
610+ * GNU Lesser General Public License for more details.
611+ *
612+ * You should have received a copy of the GNU Lesser General Public License
613+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
614+ *
615+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
616+ */
617+
618+#include "mir/graphics/platform.h"
619+#include "mir/graphics/display_report.h"
620+#include "mir/graphics/egl_resources.h"
621+#include "mir/graphics/egl_error.h"
622+#include "display_configuration.h"
623+#include "display.h"
624+#include "display_buffer.h"
625+#include "gl_context.h"
626+
627+#include <boost/throw_exception.hpp>
628+#include <fcntl.h>
629+#include <mutex>
630+
631+#define MIR_LOG_COMPONENT "x11-display"
632+#include "mir/log.h"
633+
634+namespace mg=mir::graphics;
635+namespace mgx=mg::X;
636+namespace geom=mir::geometry;
637+
638+mgx::X11EGLDisplay::X11EGLDisplay(::Display *x_dpy)
639+ : egl_dpy{eglGetDisplay(x_dpy)}
640+{
641+ if (!egl_dpy)
642+ BOOST_THROW_EXCEPTION(mg::egl_error("Cannot get an egl display"));
643+
644+ EGLint egl_major, egl_minor;
645+ if (!eglInitialize(egl_dpy, &egl_major, &egl_minor))
646+ BOOST_THROW_EXCEPTION(mg::egl_error("eglInitialize failed"));
647+
648+ mir::log_info("EGL Version %d.%d", egl_major, egl_minor);
649+}
650+
651+mgx::X11EGLDisplay::~X11EGLDisplay()
652+{
653+ eglTerminate(egl_dpy);
654+}
655+
656+mgx::X11EGLDisplay::operator EGLDisplay() const
657+{
658+ return egl_dpy;
659+}
660+
661+mgx::X11Window::X11Window(::Display *x_dpy, EGLDisplay egl_dpy, int width, int height)
662+ : x_dpy{x_dpy}
663+{
664+ EGLint const att[] = {
665+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
666+ EGL_RED_SIZE, 5,
667+ EGL_GREEN_SIZE, 5,
668+ EGL_BLUE_SIZE, 5,
669+ EGL_ALPHA_SIZE, 0,
670+ EGL_DEPTH_SIZE, 0,
671+ EGL_STENCIL_SIZE, 0,
672+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
673+ EGL_NONE
674+ };
675+
676+ auto root = XDefaultRootWindow(x_dpy);
677+
678+ EGLint num_configs;
679+ if (!eglChooseConfig(egl_dpy, att, &config, 1, &num_configs))
680+ BOOST_THROW_EXCEPTION(mg::egl_error("Cannot get an EGL config"));
681+
682+ assert(config);
683+ assert(num_configs > 0);
684+
685+ EGLint vid;
686+ if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid))
687+ BOOST_THROW_EXCEPTION(mg::egl_error("Cannot get config attrib"));
688+
689+ XVisualInfo visTemplate;
690+ int num_visuals;
691+ visTemplate.visualid = vid;
692+ auto visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
693+ if (!visInfo)
694+ BOOST_THROW_EXCEPTION(mg::egl_error("Cannot get visual info"));
695+
696+ XSetWindowAttributes attr;
697+ attr.background_pixel = 0;
698+ attr.border_pixel = 0;
699+ attr.colormap = XCreateColormap(x_dpy, root, visInfo->visual, AllocNone);
700+ attr.event_mask = StructureNotifyMask |
701+ ExposureMask |
702+ KeyPressMask |
703+ KeyReleaseMask |
704+ ButtonPressMask |
705+ ButtonReleaseMask;
706+
707+ auto mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
708+
709+ win = XCreateWindow(x_dpy, root, 0, 0, width, height,
710+ 0, visInfo->depth, InputOutput,
711+ visInfo->visual, mask, &attr);
712+
713+ mir::log_info("Pixel depth = %d", visInfo->depth);
714+
715+ //TODO: handle others
716+ assert(visInfo->depth==24);
717+
718+ XFree(visInfo);
719+
720+ XMapWindow(x_dpy, win);
721+}
722+
723+mgx::X11Window::~X11Window()
724+{
725+ XDestroyWindow(x_dpy, win);
726+}
727+
728+mgx::X11Window::operator Window() const
729+{
730+ return win;
731+}
732+
733+EGLConfig mgx::X11Window::egl_config() const
734+{
735+ return config;
736+}
737+
738+mgx::X11EGLContext::X11EGLContext(EGLDisplay egl_dpy, EGLConfig config)
739+ : egl_dpy{egl_dpy}
740+{
741+ static const EGLint ctx_attribs[] = {
742+ EGL_CONTEXT_CLIENT_VERSION, 2,
743+ EGL_NONE };
744+
745+ egl_ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, ctx_attribs);
746+ if (!egl_ctx)
747+ BOOST_THROW_EXCEPTION(mg::egl_error("eglCreateContext failed"));
748+}
749+
750+mgx::X11EGLContext::~X11EGLContext()
751+{
752+ eglDestroyContext(egl_dpy, egl_ctx);
753+}
754+
755+mgx::X11EGLContext::operator EGLContext() const
756+{
757+ return egl_ctx;
758+}
759+
760+mgx::X11EGLSurface::X11EGLSurface(EGLDisplay egl_dpy, EGLConfig config, Window win)
761+ : egl_dpy{egl_dpy}, egl_surf{eglCreateWindowSurface(egl_dpy, config, win, NULL)}
762+{
763+ if (!egl_surf)
764+ BOOST_THROW_EXCEPTION(mg::egl_error("eglCreateWindowSurface failed"));
765+}
766+
767+mgx::X11EGLSurface::~X11EGLSurface()
768+{
769+ eglDestroySurface(egl_dpy, egl_surf);
770+}
771+
772+mgx::X11EGLSurface::operator EGLSurface() const
773+{
774+ return egl_surf;
775+}
776+
777+mgx::Display::Display(::Display *dpy)
778+ : x_dpy{dpy},
779+ egl_display{X11EGLDisplay(dpy)},
780+ display_width{1280},
781+ display_height{1024},
782+ win{X11Window(dpy,
783+ egl_display,
784+ display_width,
785+ display_height)},
786+ egl_context{X11EGLContext(egl_display,
787+ win.egl_config())},
788+ egl_surface{X11EGLSurface(egl_display,
789+ win.egl_config(),
790+ win)}
791+{
792+ // TODO: read from the chosen config
793+ pf = mir_pixel_format_bgr_888;
794+
795+ // Make window nonresizeable
796+ // TODO: Make sizing possible
797+ {
798+ char const * const title = "Mir On X";
799+ XSizeHints sizehints;
800+
801+ sizehints.x = 0;
802+ sizehints.y = 0;
803+ sizehints.base_width = display_width;
804+ sizehints.base_height = display_height;
805+ sizehints.min_width = display_width;
806+ sizehints.min_height = display_height;
807+ sizehints.max_width = display_width;
808+ sizehints.max_height = display_height;
809+ sizehints.flags = USSize | USPosition | PMinSize | PMaxSize;
810+
811+ XSetNormalHints(x_dpy, win, &sizehints);
812+ XSetStandardProperties(x_dpy, win, title, title, None, (char **)NULL, 0, &sizehints);
813+ }
814+
815+ display_group = std::make_unique<mgx::DisplayGroup>(
816+ std::make_unique<mgx::DisplayBuffer>(geom::Size{display_width, display_height},
817+ egl_display,
818+ egl_surface,
819+ egl_context));
820+}
821+
822+mgx::Display::~Display() noexcept
823+{
824+ eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
825+}
826+
827+void mgx::Display::for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& f)
828+{
829+ f(*display_group);
830+}
831+
832+std::unique_ptr<mg::DisplayConfiguration> mgx::Display::configuration() const
833+{
834+ return std::make_unique<mgx::DisplayConfiguration>(pf, display_width, display_height);
835+}
836+
837+void mgx::Display::configure(mg::DisplayConfiguration const& /*new_configuration*/)
838+{
839+ BOOST_THROW_EXCEPTION(std::runtime_error("'Display::configure()' not yet supported on x11 platform"));
840+}
841+
842+void mgx::Display::register_configuration_change_handler(
843+ EventHandlerRegister& /* event_handler*/,
844+ DisplayConfigurationChangeHandler const& /*change_handler*/)
845+{
846+}
847+
848+void mgx::Display::register_pause_resume_handlers(
849+ EventHandlerRegister& /*handlers*/,
850+ DisplayPauseHandler const& /*pause_handler*/,
851+ DisplayResumeHandler const& /*resume_handler*/)
852+{
853+}
854+
855+void mgx::Display::pause()
856+{
857+ BOOST_THROW_EXCEPTION(std::runtime_error("'Display::pause()' not yet supported on x11 platform"));
858+}
859+
860+void mgx::Display::resume()
861+{
862+ BOOST_THROW_EXCEPTION(std::runtime_error("'Display::resume()' not yet supported on x11 platform"));
863+}
864+
865+auto mgx::Display::create_hardware_cursor(std::shared_ptr<mg::CursorImage> const& /* initial_image */) -> std::shared_ptr<Cursor>
866+{
867+ return nullptr;
868+}
869+
870+std::unique_ptr<mg::GLContext> mgx::Display::create_gl_context()
871+{
872+ return std::make_unique<mgx::XGLContext>(egl_display, egl_surface, egl_context);
873+}
874
875=== added file 'src/platforms/mesa/server/x11/display.h'
876--- src/platforms/mesa/server/x11/display.h 1970-01-01 00:00:00 +0000
877+++ src/platforms/mesa/server/x11/display.h 2015-07-22 20:26:39 +0000
878@@ -0,0 +1,131 @@
879+/*
880+ * Copyright © 2015 Canonical Ltd.
881+ *
882+ * This program is free software: you can redistribute it and/or modify it
883+ * under the terms of the GNU Lesser General Public License version 3,
884+ * as published by the Free Software Foundation.
885+ *
886+ * This program is distributed in the hope that it will be useful,
887+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
888+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
889+ * GNU Lesser General Public License for more details.
890+ *
891+ * You should have received a copy of the GNU Lesser General Public License
892+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
893+ *
894+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
895+ */
896+
897+#ifndef MIR_GRAPHICS_X_DISPLAY_H_
898+#define MIR_GRAPHICS_X_DISPLAY_H_
899+
900+#include "mir/graphics/display.h"
901+#include "mir_toolkit/common.h"
902+#include "display_group.h"
903+
904+#include <X11/Xlib.h>
905+#include <X11/Xutil.h>
906+#include <EGL/egl.h>
907+
908+namespace mir
909+{
910+namespace graphics
911+{
912+namespace X
913+{
914+
915+class X11EGLDisplay
916+{
917+public:
918+ X11EGLDisplay(::Display *x_dpy);
919+ ~X11EGLDisplay();
920+
921+ operator EGLDisplay() const;
922+
923+private:
924+ EGLDisplay const egl_dpy;
925+};
926+
927+class X11Window
928+{
929+public:
930+ X11Window(::Display* const x_dpy, EGLDisplay egl_dpy, int width, int height);
931+ ~X11Window();
932+
933+ operator Window() const;
934+ EGLConfig egl_config() const;
935+
936+private:
937+ ::Display* const x_dpy;
938+ Window win;
939+ EGLConfig config;
940+};
941+
942+class X11EGLContext
943+{
944+public:
945+ X11EGLContext(EGLDisplay egl_dpy, EGLConfig config);
946+ ~X11EGLContext();
947+
948+ operator EGLContext() const;
949+
950+private:
951+ EGLContext egl_ctx;
952+ EGLDisplay const egl_dpy;
953+};
954+
955+class X11EGLSurface
956+{
957+public:
958+ X11EGLSurface(EGLDisplay egl_dpy, EGLConfig config, Window win);
959+ ~X11EGLSurface();
960+
961+ operator EGLSurface() const;
962+
963+private:
964+ EGLDisplay const egl_dpy;
965+ EGLSurface const egl_surf;
966+};
967+
968+class Display : public graphics::Display
969+{
970+public:
971+ explicit Display(::Display *dpy);
972+ ~Display() noexcept;
973+
974+ void for_each_display_sync_group(std::function<void(graphics::DisplaySyncGroup&)> const& f) override;
975+
976+ std::unique_ptr<graphics::DisplayConfiguration> configuration() const override;
977+ void configure(graphics::DisplayConfiguration const&) override;
978+
979+ void register_configuration_change_handler(
980+ EventHandlerRegister& handlers,
981+ DisplayConfigurationChangeHandler const& conf_change_handler) override;
982+
983+ void register_pause_resume_handlers(
984+ EventHandlerRegister& handlers,
985+ DisplayPauseHandler const& pause_handler,
986+ DisplayResumeHandler const& resume_handler) override;
987+
988+ void pause() override;
989+ void resume() override;
990+
991+ std::shared_ptr<Cursor> create_hardware_cursor(std::shared_ptr<CursorImage> const& initial_image) override;
992+ std::unique_ptr<graphics::GLContext> create_gl_context() override;
993+
994+private:
995+ ::Display *x_dpy;
996+ X11EGLDisplay const egl_display;
997+ int const display_width;
998+ int const display_height;
999+ X11Window const win;
1000+ X11EGLContext egl_context;
1001+ X11EGLSurface egl_surface;
1002+ MirPixelFormat pf;
1003+ std::unique_ptr<DisplayGroup> display_group;
1004+};
1005+
1006+}
1007+}
1008+}
1009+#endif /* MIR_GRAPHICS_X_DISPLAY_H_ */
1010
1011=== added file 'src/platforms/mesa/server/x11/display_buffer.cpp'
1012--- src/platforms/mesa/server/x11/display_buffer.cpp 1970-01-01 00:00:00 +0000
1013+++ src/platforms/mesa/server/x11/display_buffer.cpp 2015-07-22 20:26:39 +0000
1014@@ -0,0 +1,68 @@
1015+/*
1016+ * Copyright © 2015 Canonical Ltd.
1017+ *
1018+ * This program is free software: you can redistribute it and/or modify it
1019+ * under the terms of the GNU Lesser General Public License version 3,
1020+ * as published by the Free Software Foundation.
1021+ *
1022+ * This program is distributed in the hope that it will be useful,
1023+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1024+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1025+ * GNU Lesser General Public License for more details.
1026+ *
1027+ * You should have received a copy of the GNU Lesser General Public License
1028+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1029+ *
1030+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1031+ *
1032+ */
1033+
1034+#include "mir/graphics/egl_error.h"
1035+#include "display_buffer.h"
1036+
1037+#include <boost/throw_exception.hpp>
1038+
1039+namespace mg=mir::graphics;
1040+namespace mgx=mg::X;
1041+namespace geom=mir::geometry;
1042+
1043+mgx::DisplayBuffer::DisplayBuffer(geom::Size const sz,
1044+ EGLDisplay const d,
1045+ EGLSurface const s,
1046+ EGLContext const c)
1047+ : size{sz}, egl_dpy{d}, egl_surf{s}, egl_ctx{c}
1048+{
1049+}
1050+
1051+geom::Rectangle mgx::DisplayBuffer::view_area() const
1052+{
1053+ return {{0,0}, size};
1054+}
1055+
1056+void mgx::DisplayBuffer::make_current()
1057+{
1058+ if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx))
1059+ BOOST_THROW_EXCEPTION(mg::egl_error("Cannot make current"));
1060+}
1061+
1062+void mgx::DisplayBuffer::release_current()
1063+{
1064+ if (!eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
1065+ BOOST_THROW_EXCEPTION(mg::egl_error("Cannot make uncurrent"));
1066+}
1067+
1068+bool mgx::DisplayBuffer::post_renderables_if_optimizable(RenderableList const& /*renderlist*/)
1069+{
1070+ return false;
1071+}
1072+
1073+void mgx::DisplayBuffer::gl_swap_buffers()
1074+{
1075+ if (!eglSwapBuffers(egl_dpy, egl_surf))
1076+ BOOST_THROW_EXCEPTION(mg::egl_error("Cannot swap"));
1077+}
1078+
1079+MirOrientation mgx::DisplayBuffer::orientation() const
1080+{
1081+ return mir_orientation_normal;
1082+}
1083
1084=== added file 'src/platforms/mesa/server/x11/display_buffer.h'
1085--- src/platforms/mesa/server/x11/display_buffer.h 1970-01-01 00:00:00 +0000
1086+++ src/platforms/mesa/server/x11/display_buffer.h 2015-07-22 20:26:39 +0000
1087@@ -0,0 +1,59 @@
1088+/*
1089+ * Copyright © 2015 Canonical Ltd.
1090+ *
1091+ * This program is free software: you can redistribute it and/or modify it
1092+ * under the terms of the GNU Lesser General Public License version 3,
1093+ * as published by the Free Software Foundation.
1094+ *
1095+ * This program is distributed in the hope that it will be useful,
1096+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1097+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1098+ * GNU Lesser General Public License for more details.
1099+ *
1100+ * You should have received a copy of the GNU Lesser General Public License
1101+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1102+ *
1103+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1104+ *
1105+ */
1106+
1107+#ifndef MIR_GRAPHICS_X_DISPLAY_BUFFER_H_
1108+#define MIR_GRAPHICS_X_DISPLAY_BUFFER_H_
1109+
1110+#include "mir/graphics/display_buffer.h"
1111+#include "gl_context.h"
1112+
1113+#include <EGL/egl.h>
1114+
1115+namespace mir
1116+{
1117+namespace graphics
1118+{
1119+namespace X
1120+{
1121+
1122+class DisplayBuffer : public graphics::DisplayBuffer
1123+{
1124+public:
1125+ DisplayBuffer(geometry::Size const sz, EGLDisplay const d, EGLSurface const s, EGLContext const c);
1126+
1127+ geometry::Rectangle view_area() const override;
1128+ void make_current() override;
1129+ void release_current() override;
1130+ void gl_swap_buffers() override;
1131+ bool post_renderables_if_optimizable(RenderableList const& renderlist) override;
1132+
1133+ MirOrientation orientation() const override;
1134+
1135+private:
1136+ geometry::Size const size;
1137+ EGLDisplay const egl_dpy;
1138+ EGLSurface const egl_surf;
1139+ EGLContext const egl_ctx;
1140+};
1141+
1142+}
1143+}
1144+}
1145+
1146+#endif /* MIR_GRAPHICS_X_DISPLAY_BUFFER_H_ */
1147
1148=== added file 'src/platforms/mesa/server/x11/display_configuration.cpp'
1149--- src/platforms/mesa/server/x11/display_configuration.cpp 1970-01-01 00:00:00 +0000
1150+++ src/platforms/mesa/server/x11/display_configuration.cpp 2015-07-22 20:26:39 +0000
1151@@ -0,0 +1,63 @@
1152+/*
1153+ * Copyright © 2015 Canonical Ltd.
1154+ *
1155+ * This program is free software: you can redistribute it and/or modify it
1156+ * under the terms of the GNU Lesser General Public License version 3,
1157+ * as published by the Free Software Foundation.
1158+ *
1159+ * This program is distributed in the hope that it will be useful,
1160+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1161+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1162+ * GNU Lesser General Public License for more details.
1163+ *
1164+ * You should have received a copy of the GNU Lesser General Public License
1165+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1166+ *
1167+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1168+ *
1169+ */
1170+
1171+#include "display_configuration.h"
1172+#include <boost/throw_exception.hpp>
1173+
1174+namespace mg = mir::graphics;
1175+namespace mgx = mg::X;
1176+namespace geom = mir::geometry;
1177+
1178+mgx::DisplayConfiguration::DisplayConfiguration(MirPixelFormat pf, int width, int height) :
1179+ configuration{
1180+ mg::DisplayConfigurationOutputId{1},
1181+ mg::DisplayConfigurationCardId{0},
1182+ mg::DisplayConfigurationOutputType::unknown,
1183+ {pf},
1184+ //TODO: query fps
1185+ {mg::DisplayConfigurationMode{geom::Size{width, height}, 60.0}},
1186+ 0,
1187+ //TODO: query mm-size
1188+ geom::Size{width, height},
1189+ true,
1190+ true,
1191+ geom::Point{0, 0},
1192+ 0,
1193+ pf,
1194+ mir_power_mode_on,
1195+ mir_orientation_normal},
1196+ card{mg::DisplayConfigurationCardId{0}, 1}
1197+{
1198+}
1199+
1200+void mgx::DisplayConfiguration::for_each_card(std::function<void(mg::DisplayConfigurationCard const&)> f) const
1201+{
1202+ f(card);
1203+}
1204+
1205+void mgx::DisplayConfiguration::for_each_output(std::function<void(mg::DisplayConfigurationOutput const&)> f) const
1206+{
1207+ f(configuration);
1208+}
1209+
1210+void mgx::DisplayConfiguration::for_each_output(std::function<void(mg::UserDisplayConfigurationOutput&)> f)
1211+{
1212+ mg::UserDisplayConfigurationOutput user(configuration);
1213+ f(user);
1214+}
1215
1216=== added file 'src/platforms/mesa/server/x11/display_configuration.h'
1217--- src/platforms/mesa/server/x11/display_configuration.h 1970-01-01 00:00:00 +0000
1218+++ src/platforms/mesa/server/x11/display_configuration.h 2015-07-22 20:26:39 +0000
1219@@ -0,0 +1,52 @@
1220+/*
1221+ * Copyright © 2015 Canonical Ltd.
1222+ *
1223+ * This program is free software: you can redistribute it and/or modify it
1224+ * under the terms of the GNU Lesser General Public License version 3,
1225+ * as published by the Free Software Foundation.
1226+ *
1227+ * This program is distributed in the hope that it will be useful,
1228+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1229+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1230+ * GNU Lesser General Public License for more details.
1231+ *
1232+ * You should have received a copy of the GNU Lesser General Public License
1233+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1234+ *
1235+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1236+ *
1237+ */
1238+
1239+#ifndef MIR_GRAPHICS_X_DISPLAY_CONFIGURATION_H_
1240+#define MIR_GRAPHICS_X_DISPLAY_CONFIGURATION_H_
1241+
1242+#include "mir/graphics/display_configuration.h"
1243+
1244+namespace mir
1245+{
1246+namespace graphics
1247+{
1248+namespace X
1249+{
1250+
1251+class DisplayConfiguration : public graphics::DisplayConfiguration
1252+{
1253+public:
1254+ DisplayConfiguration(MirPixelFormat pf, int width, int height);
1255+
1256+ virtual ~DisplayConfiguration() = default;
1257+
1258+ void for_each_card(std::function<void(DisplayConfigurationCard const&)> f) const override;
1259+ void for_each_output(std::function<void(DisplayConfigurationOutput const&)> f) const override;
1260+ void for_each_output(std::function<void(UserDisplayConfigurationOutput&)> f) override;
1261+
1262+private:
1263+ DisplayConfigurationOutput configuration;
1264+ DisplayConfigurationCard card;
1265+};
1266+
1267+
1268+}
1269+}
1270+}
1271+#endif /* MIR_GRAPHICS_X_DISPLAY_CONFIGURATION_H_ */
1272
1273=== added file 'src/platforms/mesa/server/x11/display_group.cpp'
1274--- src/platforms/mesa/server/x11/display_group.cpp 1970-01-01 00:00:00 +0000
1275+++ src/platforms/mesa/server/x11/display_group.cpp 2015-07-22 20:26:39 +0000
1276@@ -0,0 +1,42 @@
1277+/*
1278+ * Copyright © 2015 Canonical Ltd.
1279+ *
1280+ * This program is free software: you can redistribute it and/or modify it
1281+ * under the terms of the GNU Lesser General Public License version 3,
1282+ * as published by the Free Software Foundation.
1283+ *
1284+ * This program is distributed in the hope that it will be useful,
1285+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1286+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1287+ * GNU Lesser General Public License for more details.
1288+ *
1289+ * You should have received a copy of the GNU Lesser General Public License
1290+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1291+ *
1292+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1293+ *
1294+ */
1295+
1296+#include "display_group.h"
1297+
1298+namespace mg = mir::graphics;
1299+namespace mgx = mg::X;
1300+
1301+mgx::DisplayGroup::DisplayGroup(std::unique_ptr<mgx::DisplayBuffer> primary_buffer)
1302+{
1303+ display_buffer = std::move(primary_buffer);
1304+}
1305+
1306+void mgx::DisplayGroup::for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f)
1307+{
1308+ f(*display_buffer);
1309+}
1310+
1311+void mgx::DisplayGroup::post()
1312+{
1313+}
1314+
1315+std::chrono::milliseconds mgx::DisplayGroup::recommended_sleep() const
1316+{
1317+ return std::chrono::milliseconds::zero();
1318+}
1319
1320=== added file 'src/platforms/mesa/server/x11/display_group.h'
1321--- src/platforms/mesa/server/x11/display_group.h 1970-01-01 00:00:00 +0000
1322+++ src/platforms/mesa/server/x11/display_group.h 2015-07-22 20:26:39 +0000
1323@@ -0,0 +1,51 @@
1324+/*
1325+ * Copyright © 2015 Canonical Ltd.
1326+ *
1327+ * This program is free software: you can redistribute it and/or modify it
1328+ * under the terms of the GNU Lesser General Public License version 3,
1329+ * as published by the Free Software Foundation.
1330+ *
1331+ * This program is distributed in the hope that it will be useful,
1332+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1333+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1334+ * GNU Lesser General Public License for more details.
1335+ *
1336+ * You should have received a copy of the GNU Lesser General Public License
1337+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1338+ *
1339+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1340+ *
1341+ */
1342+
1343+#ifndef MIR_GRAPHICS_X_DISPLAY_GROUP_H_
1344+#define MIR_GRAPHICS_X_DISPLAY_GROUP_H_
1345+
1346+#include "mir_toolkit/common.h"
1347+#include "mir/graphics/display.h"
1348+#include "display_buffer.h"
1349+
1350+namespace mir
1351+{
1352+namespace graphics
1353+{
1354+namespace X
1355+{
1356+
1357+class DisplayGroup : public graphics::DisplaySyncGroup
1358+{
1359+public:
1360+ DisplayGroup(std::unique_ptr<DisplayBuffer> primary_buffer);
1361+
1362+ void for_each_display_buffer(std::function<void(graphics::DisplayBuffer&)> const& f) override;
1363+ void post() override;
1364+ std::chrono::milliseconds recommended_sleep() const override;
1365+
1366+private:
1367+ std::unique_ptr<DisplayBuffer> display_buffer;
1368+};
1369+
1370+}
1371+}
1372+}
1373+
1374+#endif /* MIR_GRAPHICS_X_DISPLAY_GROUP_H_ */
1375
1376=== added file 'src/platforms/mesa/server/x11/gl_context.cpp'
1377--- src/platforms/mesa/server/x11/gl_context.cpp 1970-01-01 00:00:00 +0000
1378+++ src/platforms/mesa/server/x11/gl_context.cpp 2015-07-22 20:26:39 +0000
1379@@ -0,0 +1,45 @@
1380+/*
1381+ * Copyright © 2015 Canonical Ltd.
1382+ *
1383+ * This program is free software: you can redistribute it and/or modify it
1384+ * under the terms of the GNU Lesser General Public License version 3,
1385+ * as published by the Free Software Foundation.
1386+ *
1387+ * This program is distributed in the hope that it will be useful,
1388+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1389+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1390+ * GNU Lesser General Public License for more details.
1391+ *
1392+ * You should have received a copy of the GNU Lesser General Public License
1393+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1394+ *
1395+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1396+ *
1397+ */
1398+
1399+#include "mir/graphics/egl_error.h"
1400+#include "gl_context.h"
1401+#include <boost/throw_exception.hpp>
1402+#include <stdexcept>
1403+
1404+namespace mg=mir::graphics;
1405+namespace mgx=mg::X;
1406+
1407+mgx::XGLContext::XGLContext(EGLDisplay const d, EGLSurface const s, EGLContext const c)
1408+ : egl_dpy{d},
1409+ egl_surf{s},
1410+ egl_ctx{c}
1411+{
1412+}
1413+
1414+void mgx::XGLContext::make_current() const
1415+{
1416+ if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx))
1417+ BOOST_THROW_EXCEPTION(mg::egl_error("Cannot make current"));
1418+}
1419+
1420+void mgx::XGLContext::release_current() const
1421+{
1422+ if (!eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
1423+ BOOST_THROW_EXCEPTION(mg::egl_error("Cannot make uncurrent"));
1424+}
1425
1426=== added file 'src/platforms/mesa/server/x11/gl_context.h'
1427--- src/platforms/mesa/server/x11/gl_context.h 1970-01-01 00:00:00 +0000
1428+++ src/platforms/mesa/server/x11/gl_context.h 2015-07-22 20:26:39 +0000
1429@@ -0,0 +1,52 @@
1430+/*
1431+ * Copyright © 2015 Canonical Ltd.
1432+ *
1433+ * This program is free software: you can redistribute it and/or modify it
1434+ * under the terms of the GNU Lesser General Public License version 3,
1435+ * as published by the Free Software Foundation.
1436+ *
1437+ * This program is distributed in the hope that it will be useful,
1438+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1439+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1440+ * GNU Lesser General Public License for more details.
1441+ *
1442+ * You should have received a copy of the GNU Lesser General Public License
1443+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1444+ *
1445+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1446+ *
1447+ */
1448+
1449+#ifndef MIR_GRAPHICS_X_GL_CONTEXT_H_
1450+#define MIR_GRAPHICS_X_GL_CONTEXT_H_
1451+
1452+#include "mir/graphics/gl_context.h"
1453+
1454+#include <EGL/egl.h>
1455+
1456+namespace mir
1457+{
1458+namespace graphics
1459+{
1460+namespace X
1461+{
1462+
1463+class XGLContext : public graphics::GLContext
1464+{
1465+public:
1466+ XGLContext(EGLDisplay const d, EGLSurface const s, EGLContext const c);
1467+ ~XGLContext() = default;
1468+ void make_current() const override;
1469+ void release_current() const override;
1470+
1471+private:
1472+ EGLDisplay const egl_dpy;
1473+ EGLSurface const egl_surf;
1474+ EGLContext const egl_ctx;
1475+};
1476+
1477+}
1478+}
1479+}
1480+
1481+#endif /* MIR_GRAPHICS_X_GL_CONTEXT_H_ */
1482
1483=== added directory 'src/platforms/mesa/server/x11/input'
1484=== added file 'src/platforms/mesa/server/x11/input/dispatchable.cpp'
1485--- src/platforms/mesa/server/x11/input/dispatchable.cpp 1970-01-01 00:00:00 +0000
1486+++ src/platforms/mesa/server/x11/input/dispatchable.cpp 2015-07-22 20:26:39 +0000
1487@@ -0,0 +1,132 @@
1488+/*
1489+ * Copyright © 2015 Canonical Ltd.
1490+ *
1491+ * This program is free software: you can redistribute it and/or modify it
1492+ * under the terms of the GNU General Public License version 3,
1493+ * as published by the Free Software Foundation.
1494+ *
1495+ * This program is distributed in the hope that it will be useful,
1496+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1497+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1498+ * GNU General Public License for more details.
1499+ *
1500+ * You should have received a copy of the GNU General Public License
1501+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1502+ *
1503+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1504+ */
1505+
1506+#include "dispatchable.h"
1507+#include "../xserver_connection.h"
1508+#include "mir/events/event_private.h"
1509+
1510+#include <boost/throw_exception.hpp>
1511+#include <chrono>
1512+#include <X11/Xlib.h>
1513+#include <X11/Xutil.h>
1514+#include <linux/input.h>
1515+#include <inttypes.h>
1516+
1517+#define MIR_LOG_COMPONENT "x11-dispatchable"
1518+#include "mir/log.h"
1519+
1520+namespace mi = mir::input;
1521+namespace mix = mi::X;
1522+namespace md = mir::dispatch;
1523+namespace mx = mir::X;
1524+
1525+extern std::shared_ptr<mx::X11Connection> x11_connection;
1526+
1527+mix::XDispatchable::XDispatchable(int raw_fd)
1528+ : fd(raw_fd), sink(nullptr)
1529+{
1530+}
1531+
1532+mir::Fd mix::XDispatchable::watch_fd() const
1533+{
1534+ return fd;
1535+}
1536+
1537+bool mix::XDispatchable::dispatch(md::FdEvents events)
1538+{
1539+ auto ret = true;
1540+
1541+ if (events & (md::FdEvent::remote_closed | md::FdEvent::error))
1542+ ret = false;
1543+
1544+ if (events & md::FdEvent::readable)
1545+ {
1546+ XEvent xev;
1547+
1548+ XNextEvent(x11_connection->dpy, &xev);
1549+
1550+ if (sink)
1551+ {
1552+ switch (xev.type)
1553+ {
1554+ case KeyPress:
1555+ case KeyRelease:
1556+ {
1557+ MirEvent event;
1558+ XKeyEvent &xkev = (XKeyEvent &)xev;
1559+ static const int STRMAX = 32;
1560+ char str[STRMAX];
1561+ KeySym keysym;
1562+
1563+ auto count = XLookupString(&xkev, str, STRMAX, &keysym, NULL);
1564+
1565+ mir::log_info("Key event : type=%d, serial=%u, send_event=%d, display=%p, window=%p, root=%p, subwindow=%p, time=%d, x=%d, y=%d, x_root=%d, y_root=%d, state=%0X, keycode=%d, same_screen=%d",
1566+ xkev.type, xkev.serial, xkev.send_event, xkev.display, xkev.window, xkev.root, xkev.subwindow, xkev.time, xkev.x, xkev.y, xkev.x_root, xkev.y_root, xkev.state, xkev.keycode, xkev.same_screen);
1567+
1568+ event.key.type = mir_event_type_key;
1569+ event.key.device_id = 0;
1570+ event.key.source_id = 0;
1571+ event.key.action = xev.type == KeyPress ?
1572+ mir_keyboard_action_down : mir_keyboard_action_up;
1573+ event.key.modifiers = mir_input_event_modifier_none;
1574+ event.key.key_code = keysym;
1575+ event.key.scan_code = xkev.keycode-8;
1576+
1577+ std::chrono::time_point<std::chrono::system_clock> tp;
1578+ std::chrono::milliseconds msec(xkev.time);
1579+ tp += msec;
1580+ event.key.event_time = std::chrono::duration_cast<std::chrono::nanoseconds>(tp.time_since_epoch());
1581+
1582+ for (int i=0; i<count; i++)
1583+ mir::log_info("buffer[%d]='%c', key_code=%d, scan_code=%d, event_time=%" PRId64, i, str[i], keysym, xkev.keycode-8, event.key.event_time);
1584+
1585+ sink->handle_input(event);
1586+ break;
1587+ }
1588+
1589+ case MappingNotify:
1590+ mir::log_info("Mapping changed at server. Refreshing the cache.");
1591+ XRefreshKeyboardMapping((XMappingEvent*)&xev);
1592+ break;
1593+
1594+ default:
1595+ mir::log_info("Uninteresting event");
1596+ break;
1597+ }
1598+ }
1599+ else
1600+ mir::log_info("input event detected with no sink to handle it");
1601+ }
1602+
1603+ return ret;
1604+}
1605+
1606+md::FdEvents mix::XDispatchable::relevant_events() const
1607+{
1608+ return md::FdEvent::readable | md::FdEvent::error | md::FdEvent::remote_closed;
1609+}
1610+
1611+void mix::XDispatchable::set_input_sink(mi::InputSink *input_sink)
1612+{
1613+ sink = input_sink;
1614+}
1615+
1616+void mix::XDispatchable::unset_input_sink()
1617+{
1618+ sink = nullptr;
1619+}
1620
1621=== added file 'src/platforms/mesa/server/x11/input/dispatchable.h'
1622--- src/platforms/mesa/server/x11/input/dispatchable.h 1970-01-01 00:00:00 +0000
1623+++ src/platforms/mesa/server/x11/input/dispatchable.h 2015-07-22 20:26:39 +0000
1624@@ -0,0 +1,52 @@
1625+/*
1626+ * Copyright © 2015 Canonical Ltd.
1627+ *
1628+ * This program is free software: you can redistribute it and/or modify it
1629+ * under the terms of the GNU Lesser General Public License version 3,
1630+ * as published by the Free Software Foundation.
1631+ *
1632+ * This program is distributed in the hope that it will be useful,
1633+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1634+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1635+ * GNU Lesser General Public License for more details.
1636+ *
1637+ * You should have received a copy of the GNU Lesser General Public License
1638+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1639+ *
1640+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1641+ */
1642+
1643+#ifndef MIR_INPUT_X_DISPATCHABLE_H_
1644+#define MIR_INPUT_X_DISPATCHABLE_H_
1645+
1646+#include "mir/dispatch/dispatchable.h"
1647+#include "mir/input/input_sink.h"
1648+
1649+namespace mir
1650+{
1651+namespace input
1652+{
1653+namespace X
1654+{
1655+struct XDispatchable : public dispatch::Dispatchable
1656+{
1657+public:
1658+ XDispatchable(int raw_fd);
1659+
1660+ mir::Fd watch_fd() const override;
1661+ bool dispatch(dispatch::FdEvents events) override;
1662+ dispatch::FdEvents relevant_events() const override;
1663+
1664+ void set_input_sink(InputSink *input_sink);
1665+ void unset_input_sink();
1666+
1667+private:
1668+ mir::Fd fd;
1669+ InputSink *sink;
1670+};
1671+
1672+}
1673+}
1674+}
1675+
1676+#endif // MIR_INPUT_X_DISPATCHABLE_H_
1677
1678=== added file 'src/platforms/mesa/server/x11/input/input.cpp'
1679--- src/platforms/mesa/server/x11/input/input.cpp 1970-01-01 00:00:00 +0000
1680+++ src/platforms/mesa/server/x11/input/input.cpp 2015-07-22 20:26:39 +0000
1681@@ -0,0 +1,60 @@
1682+/*
1683+ * Copyright © 2015 Canonical Ltd.
1684+ *
1685+ * This program is free software: you can redistribute it and/or modify it
1686+ * under the terms of the GNU General Public License version 3,
1687+ * as published by the Free Software Foundation.
1688+ *
1689+ * This program is distributed in the hope that it will be useful,
1690+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1691+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1692+ * GNU General Public License for more details.
1693+ *
1694+ * You should have received a copy of the GNU General Public License
1695+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1696+ *
1697+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1698+ */
1699+
1700+#include "input_platform.h"
1701+#include "mir/module_properties.h"
1702+#include "mir/input/platform.h"
1703+
1704+namespace mo = mir::options;
1705+namespace mi = mir::input;
1706+namespace mix = mi::X;
1707+
1708+extern "C" mir::UniqueModulePtr<mi::Platform> create_input_platform(
1709+ std::shared_ptr<mo::Option> const& /*options*/,
1710+ std::shared_ptr<mir::EmergencyCleanupRegistry> const& /*emergency_cleanup_registry*/,
1711+ std::shared_ptr<mi::InputDeviceRegistry> const& input_device_registry,
1712+ std::shared_ptr<mi::InputReport> const& /*report*/)
1713+{
1714+ return mir::make_module_ptr<mix::XInputPlatform>(input_device_registry);
1715+}
1716+
1717+extern "C" void add_input_platform_options(
1718+ boost::program_options::options_description& /*config*/)
1719+{
1720+}
1721+
1722+extern "C" mi::PlatformPriority probe_input_platform(
1723+ mo::Option const& /*options*/)
1724+{
1725+ return mi::PlatformPriority::best;
1726+}
1727+
1728+namespace
1729+{
1730+mir::ModuleProperties const description = {
1731+ "x11-input",
1732+ MIR_VERSION_MAJOR,
1733+ MIR_VERSION_MINOR,
1734+ MIR_VERSION_MICRO
1735+};
1736+}
1737+
1738+extern "C" mir::ModuleProperties const* describe_input_module()
1739+{
1740+ return &description;
1741+}
1742
1743=== added file 'src/platforms/mesa/server/x11/input/input_device.cpp'
1744--- src/platforms/mesa/server/x11/input/input_device.cpp 1970-01-01 00:00:00 +0000
1745+++ src/platforms/mesa/server/x11/input/input_device.cpp 2015-07-22 20:26:39 +0000
1746@@ -0,0 +1,54 @@
1747+/*
1748+ * Copyright © 2015 Canonical Ltd.
1749+ *
1750+ * This program is free software: you can redistribute it and/or modify it
1751+ * under the terms of the GNU General Public License version 3,
1752+ * as published by the Free Software Foundation.
1753+ *
1754+ * This program is distributed in the hope that it will be useful,
1755+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1756+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1757+ * GNU General Public License for more details.
1758+ *
1759+ * You should have received a copy of the GNU General Public License
1760+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1761+ *
1762+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1763+ */
1764+
1765+#include "mir/input/input_device_info.h"
1766+#include "input_device.h"
1767+#include "dispatchable.h"
1768+#include "../xserver_connection.h"
1769+
1770+namespace mi = mir::input;
1771+namespace mix = mi::X;
1772+namespace md = mir::dispatch;
1773+namespace mx = mir::X;
1774+
1775+extern std::shared_ptr<mx::X11Connection> x11_connection;
1776+
1777+mix::XInputDevice::XInputDevice()
1778+ : fd(XConnectionNumber(x11_connection->dpy)), x_dispatchable(std::make_shared<mix::XDispatchable>(fd))
1779+{
1780+}
1781+
1782+std::shared_ptr<md::Dispatchable> mix::XInputDevice::dispatchable()
1783+{
1784+ return x_dispatchable;
1785+}
1786+
1787+void mix::XInputDevice::start(mi::InputSink* destination)
1788+{
1789+ x_dispatchable->set_input_sink(destination);
1790+}
1791+
1792+void mix::XInputDevice::stop()
1793+{
1794+ x_dispatchable->unset_input_sink();
1795+}
1796+
1797+mi::InputDeviceInfo mix::XInputDevice::get_device_info()
1798+{
1799+ return mi::InputDeviceInfo{0,"x11-keyboard-device","x11-key-dev-1", mi::DeviceCapability::keyboard};
1800+}
1801
1802=== added file 'src/platforms/mesa/server/x11/input/input_device.h'
1803--- src/platforms/mesa/server/x11/input/input_device.h 1970-01-01 00:00:00 +0000
1804+++ src/platforms/mesa/server/x11/input/input_device.h 2015-07-22 20:26:39 +0000
1805@@ -0,0 +1,66 @@
1806+/*
1807+ * Copyright © 2015 Canonical Ltd.
1808+ *
1809+ * This program is free software: you can redistribute it and/or modify it
1810+ * under the terms of the GNU Lesser General Public License version 3,
1811+ * as published by the Free Software Foundation.
1812+ *
1813+ * This program is distributed in the hope that it will be useful,
1814+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1815+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1816+ * GNU Lesser General Public License for more details.
1817+ *
1818+ * You should have received a copy of the GNU Lesser General Public License
1819+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1820+ *
1821+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1822+ */
1823+
1824+#ifndef MIR_INPUT_X_INPUT_DEVICE_H_
1825+#define MIR_INPUT_X_INPUT_DEVICE_H_
1826+
1827+#include "mir/input/input_device.h"
1828+
1829+#include <X11/Xlib.h>
1830+
1831+namespace mir
1832+{
1833+
1834+namespace dispatch
1835+{
1836+class Dispatchable;
1837+}
1838+
1839+namespace input
1840+{
1841+
1842+namespace X
1843+{
1844+class XDispatchable;
1845+
1846+class XInputDevice : public input::InputDevice
1847+{
1848+public:
1849+ XInputDevice();
1850+ ~XInputDevice() = default;
1851+
1852+ std::shared_ptr<dispatch::Dispatchable> dispatchable() override;
1853+ void start(input::InputSink* destination) override;
1854+ void stop() override;
1855+ InputDeviceInfo get_device_info() override;
1856+
1857+protected:
1858+ XInputDevice(XInputDevice const&) = delete;
1859+ XInputDevice& operator=(XInputDevice const&) = delete;
1860+
1861+private:
1862+ int fd;
1863+ std::shared_ptr<XDispatchable> x_dispatchable;
1864+};
1865+
1866+}
1867+
1868+}
1869+}
1870+
1871+#endif // MIR_INPUT_X_INPUT_DEVICE_H_
1872
1873=== added file 'src/platforms/mesa/server/x11/input/input_platform.cpp'
1874--- src/platforms/mesa/server/x11/input/input_platform.cpp 1970-01-01 00:00:00 +0000
1875+++ src/platforms/mesa/server/x11/input/input_platform.cpp 2015-07-22 20:26:39 +0000
1876@@ -0,0 +1,51 @@
1877+/*
1878+ * Copyright © 2015 Canonical Ltd.
1879+ *
1880+ * This program is free software: you can redistribute it and/or modify it
1881+ * under the terms of the GNU General Public License version 3,
1882+ * as published by the Free Software Foundation.
1883+ *
1884+ * This program is distributed in the hope that it will be useful,
1885+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1886+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1887+ * GNU General Public License for more details.
1888+ *
1889+ * You should have received a copy of the GNU General Public License
1890+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1891+ *
1892+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1893+ */
1894+
1895+#include "input_platform.h"
1896+#include "input_device.h"
1897+
1898+#include "mir/input/input_device_registry.h"
1899+#include "mir/dispatch/action_queue.h"
1900+#include "mir/module_deleter.h"
1901+
1902+namespace mi = mir::input;
1903+namespace md = mir::dispatch;
1904+namespace mix = mi::X;
1905+
1906+mix::XInputPlatform::XInputPlatform(
1907+ std::shared_ptr<mi::InputDeviceRegistry> const& input_device_registry)
1908+ : platform_queue(mir::make_module_ptr<md::ActionQueue>()),
1909+ registry(input_device_registry),
1910+ device(std::make_shared<mix::XInputDevice>())
1911+{
1912+}
1913+
1914+void mix::XInputPlatform::start()
1915+{
1916+ registry->add_device(device);
1917+}
1918+
1919+std::shared_ptr<md::Dispatchable> mix::XInputPlatform::dispatchable()
1920+{
1921+ return platform_queue;
1922+}
1923+
1924+void mix::XInputPlatform::stop()
1925+{
1926+ registry->remove_device(device);
1927+}
1928
1929=== added file 'src/platforms/mesa/server/x11/input/input_platform.h'
1930--- src/platforms/mesa/server/x11/input/input_platform.h 1970-01-01 00:00:00 +0000
1931+++ src/platforms/mesa/server/x11/input/input_platform.h 2015-07-22 20:26:39 +0000
1932@@ -0,0 +1,60 @@
1933+/*
1934+ * Copyright © 2015 Canonical Ltd.
1935+ *
1936+ * This program is free software: you can redistribute it and/or modify it
1937+ * under the terms of the GNU General Public License version 3,
1938+ * as published by the Free Software Foundation.
1939+ *
1940+ * This program is distributed in the hope that it will be useful,
1941+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1942+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1943+ * GNU General Public License for more details.
1944+ *
1945+ * You should have received a copy of the GNU General Public License
1946+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1947+ *
1948+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1949+ */
1950+#ifndef MIR_INPUT_X_INPUT_PLATFORM_H_
1951+#define MIR_INPUT_X_INPUT_PLATFORM_H_
1952+
1953+#include "mir/input/platform.h"
1954+#include <memory>
1955+
1956+namespace mir
1957+{
1958+
1959+namespace dispatch
1960+{
1961+class ActionQueue;
1962+}
1963+
1964+namespace input
1965+{
1966+class InputDevice;
1967+
1968+namespace X
1969+{
1970+class XInputDevice;
1971+
1972+class XInputPlatform : public input::Platform
1973+{
1974+public:
1975+ explicit XInputPlatform(std::shared_ptr<input::InputDeviceRegistry> const& input_device_registry);
1976+ ~XInputPlatform() = default;
1977+
1978+ std::shared_ptr<dispatch::Dispatchable> dispatchable() override;
1979+ void start() override;
1980+ void stop() override;
1981+
1982+private:
1983+ std::shared_ptr<dispatch::ActionQueue> const platform_queue;
1984+ std::shared_ptr<input::InputDeviceRegistry> const registry;
1985+ std::shared_ptr<XInputDevice> const device;
1986+};
1987+
1988+}
1989+}
1990+}
1991+
1992+#endif // MIR_INPUT_X_INPUT_PLATFORM_H_
1993
1994=== added file 'src/platforms/mesa/server/x11/platform.cpp'
1995--- src/platforms/mesa/server/x11/platform.cpp 1970-01-01 00:00:00 +0000
1996+++ src/platforms/mesa/server/x11/platform.cpp 2015-07-22 20:26:39 +0000
1997@@ -0,0 +1,135 @@
1998+/*
1999+ * Copyright © 2015 Canonical Ltd.
2000+ *
2001+ * This program is free software: you can redistribute it and/or modify it
2002+ * under the terms of the GNU Lesser General Public License version 3,
2003+ * as published by the Free Software Foundation.
2004+ *
2005+ * This program is distributed in the hope that it will be useful,
2006+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2007+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008+ * GNU Lesser General Public License for more details.
2009+ *
2010+ * You should have received a copy of the GNU Lesser General Public License
2011+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2012+ *
2013+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
2014+ */
2015+
2016+#include "platform.h"
2017+#include "display.h"
2018+#include "buffer_allocator.h"
2019+#include "ipc_operations.h"
2020+#include "xserver_connection.h"
2021+#include "mir/udev/wrapper.h"
2022+
2023+#include <boost/throw_exception.hpp>
2024+
2025+namespace mg = mir::graphics;
2026+namespace mgm = mg::mesa;
2027+namespace mgx = mg::X;
2028+namespace mo = mir::options;
2029+namespace mx = mir::X;
2030+
2031+//TODO: Remove this global by allowing input and graphics drivers to share
2032+// some context like the x11 display handle.
2033+std::shared_ptr<mx::X11Connection> x11_connection;
2034+
2035+mgx::Platform::Platform()
2036+ : udev{std::make_shared<mir::udev::Context>()},
2037+ drm{std::make_shared<mesa::helpers::DRMHelper>(mesa::helpers::DRMNodeToUse::render)}
2038+{
2039+ if (x11_connection)
2040+ BOOST_THROW_EXCEPTION(std::runtime_error("Cannot create x11 platform more than once"));
2041+
2042+ x11_connection.reset(new mx::X11Connection());
2043+
2044+ if (!x11_connection->dpy)
2045+ BOOST_THROW_EXCEPTION(std::runtime_error("Cannot open x11 display"));
2046+
2047+ drm->setup(udev);
2048+ gbm.setup(*drm);
2049+}
2050+
2051+std::shared_ptr<mg::GraphicBufferAllocator> mgx::Platform::create_buffer_allocator()
2052+{
2053+ return std::make_shared<mgm::BufferAllocator>(gbm.device, mgm::BypassOption::prohibited, mgm::BufferImportMethod::dma_buf);
2054+}
2055+
2056+std::shared_ptr<mg::Display> mgx::Platform::create_display(
2057+ std::shared_ptr<DisplayConfigurationPolicy> const& /*initial_conf_policy*/,
2058+ std::shared_ptr<GLProgramFactory> const&,
2059+ std::shared_ptr<GLConfig> const& /*gl_config*/)
2060+{
2061+ return std::make_shared<mgx::Display>(x11_connection->dpy);
2062+}
2063+
2064+std::shared_ptr<mg::PlatformIpcOperations> mgx::Platform::make_ipc_operations() const
2065+{
2066+ return std::make_shared<mg::mesa::IpcOperations>(drm);
2067+}
2068+
2069+EGLNativeDisplayType mgx::Platform::egl_native_display() const
2070+{
2071+ return eglGetDisplay(x11_connection->dpy);
2072+}
2073+
2074+////////////////////////////////////////////////////////////////////////////////////
2075+// Platform module entry points below
2076+////////////////////////////////////////////////////////////////////////////////////
2077+
2078+std::shared_ptr<mg::Platform> create_host_platform(
2079+ std::shared_ptr<mo::Option> const& /*options*/,
2080+ std::shared_ptr<mir::EmergencyCleanupRegistry> const& /*emergency_cleanup_registry*/,
2081+ std::shared_ptr<mg::DisplayReport> const& /*report*/)
2082+{
2083+ return std::make_shared<mgx::Platform>();
2084+}
2085+
2086+std::shared_ptr<mg::Platform> create_guest_platform(
2087+ std::shared_ptr<mg::DisplayReport> const& /*report*/,
2088+ std::shared_ptr<mg::NestedContext> const&)
2089+{
2090+ BOOST_THROW_EXCEPTION(std::runtime_error("Guest platform isn't supported under X"));
2091+ return nullptr;
2092+}
2093+
2094+void add_graphics_platform_options(boost::program_options::options_description& /*config*/)
2095+{
2096+}
2097+
2098+mg::PlatformPriority probe_graphics_platform(mo::ProgramOption const& /*options*/)
2099+{
2100+ auto dpy = XOpenDisplay(nullptr);
2101+ if (dpy)
2102+ {
2103+ XCloseDisplay(dpy);
2104+
2105+ auto udev = std::make_shared<mir::udev::Context>();
2106+
2107+ mir::udev::Enumerator drm_devices{udev};
2108+ drm_devices.match_subsystem("drm");
2109+ drm_devices.match_sysname("renderD[0-9]*");
2110+ drm_devices.scan_devices();
2111+
2112+ for (auto& device : drm_devices)
2113+ {
2114+ static_cast<void>(device);
2115+
2116+ return mg::PlatformPriority::best;
2117+ }
2118+ }
2119+ return mg::PlatformPriority::unsupported;
2120+}
2121+
2122+mir::ModuleProperties const description = {
2123+ "mesa-x11",
2124+ MIR_VERSION_MAJOR,
2125+ MIR_VERSION_MINOR,
2126+ MIR_VERSION_MICRO
2127+};
2128+
2129+mir::ModuleProperties const* describe_graphics_module()
2130+{
2131+ return &description;
2132+}
2133
2134=== added file 'src/platforms/mesa/server/x11/platform.h'
2135--- src/platforms/mesa/server/x11/platform.h 1970-01-01 00:00:00 +0000
2136+++ src/platforms/mesa/server/x11/platform.h 2015-07-22 20:26:39 +0000
2137@@ -0,0 +1,61 @@
2138+/*
2139+ * Copyright © 2015 Canonical Ltd.
2140+ *
2141+ * This program is free software: you can redistribute it and/or modify it
2142+ * under the terms of the GNU Lesser General Public License version 3,
2143+ * as published by the Free Software Foundation.
2144+ *
2145+ * This program is distributed in the hope that it will be useful,
2146+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2147+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2148+ * GNU Lesser General Public License for more details.
2149+ *
2150+ * You should have received a copy of the GNU Lesser General Public License
2151+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2152+ *
2153+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
2154+ */
2155+
2156+#ifndef MIR_GRAPHICS_X_PLATFORM_H_
2157+#define MIR_GRAPHICS_X_PLATFORM_H_
2158+
2159+#include "mir/graphics/platform.h"
2160+#include "display_helpers.h"
2161+
2162+#include <X11/Xlib.h>
2163+#include <X11/Xutil.h>
2164+
2165+namespace mir
2166+{
2167+namespace graphics
2168+{
2169+namespace X
2170+{
2171+
2172+class Platform : public graphics::Platform
2173+{
2174+public:
2175+ explicit Platform();
2176+ ~Platform() = default;
2177+
2178+ /* From Platform */
2179+ std::shared_ptr<graphics::GraphicBufferAllocator> create_buffer_allocator() override;
2180+
2181+ std::shared_ptr<graphics::Display> create_display(
2182+ std::shared_ptr<DisplayConfigurationPolicy> const& initial_conf_policy,
2183+ std::shared_ptr<GLProgramFactory> const& program_factory,
2184+ std::shared_ptr<GLConfig> const& gl_config) override;
2185+
2186+ std::shared_ptr<PlatformIpcOperations> make_ipc_operations() const override;
2187+
2188+ EGLNativeDisplayType egl_native_display() const override;
2189+private:
2190+ std::shared_ptr<mir::udev::Context> udev;
2191+ std::shared_ptr<mesa::helpers::DRMHelper> const drm;
2192+ mesa::helpers::GBMHelper gbm;
2193+};
2194+
2195+}
2196+}
2197+}
2198+#endif /* MIR_GRAPHICS_X_PLATFORM_H_ */
2199
2200=== added file 'src/platforms/mesa/server/x11/symbols.map'
2201--- src/platforms/mesa/server/x11/symbols.map 1970-01-01 00:00:00 +0000
2202+++ src/platforms/mesa/server/x11/symbols.map 2015-07-22 20:26:39 +0000
2203@@ -0,0 +1,18 @@
2204+MIR_GRAPHICS_PLATFORM_4 {
2205+ global:
2206+ add_graphics_platform_options;
2207+ probe_graphics_platform;
2208+ create_host_platform;
2209+ create_guest_platform;
2210+ describe_graphics_module;
2211+ local: *;
2212+};
2213+
2214+MIR_INPUT_PLATFORM_1 {
2215+ global:
2216+ add_input_platform_options;
2217+ create_input_platform;
2218+ probe_input_platform;
2219+ describe_input_module;
2220+ local: *;
2221+};
2222
2223=== added file 'src/platforms/mesa/server/x11/xserver_connection.h'
2224--- src/platforms/mesa/server/x11/xserver_connection.h 1970-01-01 00:00:00 +0000
2225+++ src/platforms/mesa/server/x11/xserver_connection.h 2015-07-22 20:26:39 +0000
2226@@ -0,0 +1,47 @@
2227+/*
2228+ * Copyright © 2015 Canonical Ltd.
2229+ *
2230+ * This program is free software: you can redistribute it and/or modify it
2231+ * under the terms of the GNU Lesser General Public License version 3,
2232+ * as published by the Free Software Foundation.
2233+ *
2234+ * This program is distributed in the hope that it will be useful,
2235+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2236+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2237+ * GNU Lesser General Public License for more details.
2238+ *
2239+ * You should have received a copy of the GNU Lesser General Public License
2240+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2241+ *
2242+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
2243+ */
2244+
2245+#ifndef MIR_X_XSERVER_CONNECTION_H_
2246+#define MIR_X_XSERVER_CONNECTION_H_
2247+
2248+#include <X11/Xlib.h>
2249+#include <X11/Xutil.h>
2250+
2251+namespace mir
2252+{
2253+namespace X
2254+{
2255+
2256+struct X11Connection
2257+{
2258+ X11Connection()
2259+ {
2260+ dpy = XOpenDisplay(nullptr);
2261+ }
2262+
2263+ ~X11Connection()
2264+ {
2265+ XCloseDisplay(dpy);
2266+ }
2267+
2268+ ::Display *dpy;
2269+};
2270+
2271+}
2272+}
2273+#endif /* MIR_X_XSERVER_CONNECTION_H_ */
2274
2275=== modified file 'tests/CMakeLists.txt'
2276--- tests/CMakeLists.txt 2015-06-29 03:29:31 +0000
2277+++ tests/CMakeLists.txt 2015-07-22 20:26:39 +0000
2278@@ -33,6 +33,10 @@
2279 add_definitions(-DMESA_KMS)
2280 endif()
2281
2282+if (MIR_TEST_PLATFORM STREQUAL "mesa-x11")
2283+ add_definitions(-DMESA_X11)
2284+endif()
2285+
2286 if (MIR_BUILD_PLATFORM_ANDROID)
2287 #avoid complaints about poor quality android headers
2288 include_directories(SYSTEM ${LIBHARDWARE_INCLUDE_DIRS})
2289
2290=== modified file 'tests/acceptance-tests/test_client_library.cpp'
2291--- tests/acceptance-tests/test_client_library.cpp 2015-07-16 07:03:19 +0000
2292+++ tests/acceptance-tests/test_client_library.cpp 2015-07-22 20:26:39 +0000
2293@@ -421,7 +421,7 @@
2294 }
2295 #endif
2296
2297-#ifdef ANDROID
2298+#if defined(ANDROID) || defined(MESA_X11)
2299 // Mir's Android test infrastructure isn't quite ready for this yet.
2300 TEST_F(ClientLibrary, DISABLED_gets_buffer_dimensions)
2301 #else
2302@@ -646,10 +646,10 @@
2303 * trying to marshall stub buffers causes crashes.
2304 */
2305
2306-#ifndef ANDROID
2307+#if defined(ANDROID) || defined(MESA_X11)
2308+TEST_F(ClientLibrary, DISABLED_create_simple_normal_surface_from_spec)
2309+#else
2310 TEST_F(ClientLibrary, create_simple_normal_surface_from_spec)
2311-#else
2312-TEST_F(ClientLibrary, DISABLED_create_simple_normal_surface_from_spec)
2313 #endif
2314 {
2315 auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
2316@@ -677,10 +677,10 @@
2317 mir_connection_release(connection);
2318 }
2319
2320-#ifndef ANDROID
2321+#if defined(ANDROID) || defined(MESA_X11)
2322+TEST_F(ClientLibrary, DISABLED_create_simple_normal_surface_from_spec_async)
2323+#else
2324 TEST_F(ClientLibrary, create_simple_normal_surface_from_spec_async)
2325-#else
2326-TEST_F(ClientLibrary, DISABLED_create_simple_normal_surface_from_spec_async)
2327 #endif
2328 {
2329 auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
2330@@ -744,10 +744,10 @@
2331 mir_connection_release(connection);
2332 }
2333
2334-#ifndef ANDROID
2335+#if defined(ANDROID) || defined(MESA_X11)
2336+TEST_F(ClientLibrary, DISABLED_set_fullscreen_on_output_makes_fullscreen_surface)
2337+#else
2338 TEST_F(ClientLibrary, set_fullscreen_on_output_makes_fullscreen_surface)
2339-#else
2340-TEST_F(ClientLibrary, DISABLED_set_fullscreen_on_output_makes_fullscreen_surface)
2341 #endif
2342 {
2343 using namespace testing;
2344
2345=== added file 'tests/include/mir/test/doubles/mock_input_sink.h'
2346--- tests/include/mir/test/doubles/mock_input_sink.h 1970-01-01 00:00:00 +0000
2347+++ tests/include/mir/test/doubles/mock_input_sink.h 2015-07-22 20:26:39 +0000
2348@@ -0,0 +1,44 @@
2349+/*
2350+ * Copyright © 2015 Canonical Ltd.
2351+ *
2352+ * This program is free software: you can redistribute it and/or modify it
2353+ * under the terms of the GNU General Public License version 3,
2354+ * as published by the Free Software Foundation.
2355+ *
2356+ * This program is distributed in the hope that it will be useful,
2357+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2358+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2359+ * GNU General Public License for more details.
2360+ *
2361+ * You should have received a copy of the GNU General Public License
2362+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2363+ *
2364+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
2365+ */
2366+
2367+#ifndef MIR_TEST_DOUBLES_MOCK_INPUT_SINK_H_
2368+#define MIR_TEST_DOUBLES_MOCK_INPUT_SINK_H_
2369+
2370+#include "mir/input/input_sink.h"
2371+
2372+#include <gmock/gmock.h>
2373+
2374+namespace mir
2375+{
2376+namespace test
2377+{
2378+namespace doubles
2379+{
2380+
2381+struct MockInputSink : mir::input::InputSink
2382+{
2383+ MOCK_METHOD1(handle_input, void(MirEvent&));
2384+ MOCK_METHOD1(confine_pointer, void(mir::geometry::Point&));
2385+ MOCK_CONST_METHOD0(bounding_rectangle, mir::geometry::Rectangle());
2386+};
2387+
2388+}
2389+}
2390+}
2391+
2392+#endif // MIR_TEST_DOUBLES_MOCK_INPUT_SINK_H_
2393
2394=== added file 'tests/include/mir/test/doubles/mock_x11.h'
2395--- tests/include/mir/test/doubles/mock_x11.h 1970-01-01 00:00:00 +0000
2396+++ tests/include/mir/test/doubles/mock_x11.h 2015-07-22 20:26:39 +0000
2397@@ -0,0 +1,78 @@
2398+/*
2399+ * Copyright © 2015 Canonical Ltd.
2400+ *
2401+ * This program is free software: you can redistribute it and/or modify
2402+ * it under the terms of the GNU General Public License version 3 as
2403+ * published by the Free Software Foundation.
2404+ *
2405+ * This program is distributed in the hope that it will be useful,
2406+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2407+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2408+ * GNU General Public License for more details.
2409+ *
2410+ * You should have received a copy of the GNU General Public License
2411+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2412+ *
2413+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
2414+ */
2415+
2416+#ifndef MIR_TEST_DOUBLES_MOCK_X11_H_
2417+#define MIR_TEST_DOUBLES_MOCK_X11_H_
2418+
2419+#include <gmock/gmock.h>
2420+
2421+#include <X11/Xlib.h>
2422+#include <X11/Xutil.h>
2423+
2424+namespace mir
2425+{
2426+namespace test
2427+{
2428+namespace doubles
2429+{
2430+
2431+class FakeX11Resources
2432+{
2433+public:
2434+ FakeX11Resources();
2435+ ~FakeX11Resources() = default;
2436+
2437+ Display *display;
2438+ Window window;
2439+ XVisualInfo visual_info;
2440+ XEvent event_return;
2441+};
2442+
2443+class MockX11
2444+{
2445+public:
2446+ MockX11();
2447+ ~MockX11();
2448+
2449+ MOCK_METHOD1(XOpenDisplay, Display*(const char*));
2450+ MOCK_METHOD1(XCloseDisplay, int(Display*));
2451+ MOCK_METHOD4(XGetVisualInfo, XVisualInfo*(Display*, long, XVisualInfo*, int*));
2452+ MOCK_METHOD4(XCreateColormap, Colormap(Display*, Window, Visual*, int));
2453+ /* Too long to mock, use wrapper instead.
2454+ MOCK_METHOD12(XCreateWindow, Window(Display*, Window, int, int, unsigned int, unsigned int, unsigned int, int, unsigned int, Visual*, unsigned long, XSetWindowAttributes*));
2455+ */
2456+ MOCK_METHOD10(XCreateWindow_wrapper, Window(Display*, Window, unsigned int, unsigned int, unsigned int, int, unsigned int, Visual*, unsigned long, XSetWindowAttributes*));
2457+ MOCK_METHOD3(XSetNormalHints, int(Display*, Window, XSizeHints*));
2458+ MOCK_METHOD8(XSetStandardProperties, int(Display*, Window, const char*, const char*, Pixmap, char **, int, XSizeHints*));
2459+ MOCK_METHOD1(XFree, int(void*));
2460+ MOCK_METHOD2(XMapWindow, int(Display*, Window));
2461+ MOCK_METHOD2(XDestroyWindow, int(Display*, Window));
2462+ MOCK_METHOD1(XConnectionNumber, int(Display*));
2463+ MOCK_METHOD2(XNextEvent, int(Display*, XEvent*));
2464+ MOCK_METHOD5(XLookupString, int(XKeyEvent*, char*, int, KeySym*, XComposeStatus*));
2465+ MOCK_METHOD1(XRefreshKeyboardMapping, int(XMappingEvent*));
2466+ MOCK_METHOD1(XDefaultRootWindow, Window(Display*));
2467+
2468+ FakeX11Resources fake_x11;
2469+};
2470+
2471+}
2472+}
2473+}
2474+
2475+#endif /* MIR_TEST_DOUBLES_MOCK_X11_H_ */
2476
2477=== modified file 'tests/mir_test_doubles/CMakeLists.txt'
2478--- tests/mir_test_doubles/CMakeLists.txt 2015-06-26 08:00:59 +0000
2479+++ tests/mir_test_doubles/CMakeLists.txt 2015-07-22 20:26:39 +0000
2480@@ -28,6 +28,12 @@
2481 ${CMAKE_CURRENT_SOURCE_DIR}/mock_gl.cpp
2482 )
2483
2484+if (MIR_BUILD_PLATFORM_MESA_X11)
2485+ list(APPEND MIR_TEST_DOUBLES_PLATFORM_SRCS
2486+ ${CMAKE_CURRENT_SOURCE_DIR}/mock_x11.cpp
2487+ )
2488+endif()
2489+
2490 if (MIR_BUILD_PLATFORM_MESA_KMS)
2491 include_directories(
2492 ${PROJECT_SOURCE_DIR}/src/platforms/mesa/server/common
2493
2494=== added file 'tests/mir_test_doubles/mock_x11.cpp'
2495--- tests/mir_test_doubles/mock_x11.cpp 1970-01-01 00:00:00 +0000
2496+++ tests/mir_test_doubles/mock_x11.cpp 2015-07-22 20:26:39 +0000
2497@@ -0,0 +1,133 @@
2498+/*
2499+ * Copyright © 2015 Canonical Ltd.
2500+ *
2501+ * This program is free software: you can redistribute it and/or modify
2502+ * it under the terms of the GNU General Public License version 3 as
2503+ * published by the Free Software Foundation.
2504+ *
2505+ * This program is distributed in the hope that it will be useful,
2506+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2507+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2508+ * GNU General Public License for more details.
2509+ *
2510+ * You should have received a copy of the GNU General Public License
2511+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2512+ *
2513+ * Authored by:
2514+ * Cemil Azizoglu <cemil.azizoglu@canonical.com>
2515+ */
2516+
2517+#include "mir/test/doubles/mock_x11.h"
2518+#include <gtest/gtest.h>
2519+
2520+namespace mtd=mir::test::doubles;
2521+
2522+namespace
2523+{
2524+mtd::MockX11* global_mock = nullptr;
2525+}
2526+
2527+mtd::FakeX11Resources::FakeX11Resources()
2528+ : display{reinterpret_cast<Display*>(0x12345678)},
2529+ window{reinterpret_cast<Window>((long unsigned int)9876543210)}
2530+{
2531+ visual_info.depth=24;
2532+ event_return.type = KeyPress;
2533+}
2534+
2535+mtd::MockX11::MockX11()
2536+{
2537+ using namespace testing;
2538+ assert(global_mock == nullptr && "Only one mock object per process is allowed");
2539+
2540+ global_mock = this;
2541+
2542+ ON_CALL(*this, XOpenDisplay(_))
2543+ .WillByDefault(Return(fake_x11.display));
2544+
2545+ ON_CALL(*this, XGetVisualInfo(fake_x11.display,_,_,_))
2546+ .WillByDefault(Return(&fake_x11.visual_info));
2547+
2548+ ON_CALL(*this, XCreateWindow_wrapper(fake_x11.display,_,_,_,_,_,_,_,_,_))
2549+ .WillByDefault(Return(fake_x11.window));
2550+}
2551+
2552+mtd::MockX11::~MockX11()
2553+{
2554+ global_mock = nullptr;
2555+}
2556+
2557+Display *XOpenDisplay(const char *display_name)
2558+{
2559+ return global_mock->XOpenDisplay(display_name);
2560+}
2561+
2562+int XCloseDisplay(Display *display)
2563+{
2564+ return global_mock->XCloseDisplay(display);
2565+}
2566+
2567+XVisualInfo *XGetVisualInfo(Display *display, long vinfo_mask, XVisualInfo *vinfo_template, int *nitems_return)
2568+{
2569+ return global_mock->XGetVisualInfo(display, vinfo_mask, vinfo_template, nitems_return);
2570+}
2571+
2572+Colormap XCreateColormap(Display *display, Window w, Visual *visual, int alloc)
2573+{
2574+ return global_mock->XCreateColormap(display, w, visual, alloc);
2575+}
2576+
2577+Window XCreateWindow(Display * display, Window parent, int /*x*/, int /*y*/, unsigned int width, unsigned int height, unsigned int border_width, int depth, unsigned int clss, Visual *visual, unsigned long valuemask, XSetWindowAttributes *attributes)
2578+{
2579+ return global_mock->XCreateWindow_wrapper(display, parent, width, height, border_width, depth, clss, visual, valuemask, attributes);
2580+}
2581+
2582+int XSetNormalHints(Display *display, Window w, XSizeHints *hints)
2583+{
2584+ return global_mock->XSetNormalHints(display, w, hints);
2585+}
2586+
2587+int XSetStandardProperties(Display *display, Window w, const char *window_name, const char *icon_name, Pixmap icon_pixmap, char **argv, int argc, XSizeHints *hints)
2588+{
2589+ return global_mock->XSetStandardProperties(display, w, window_name, icon_name, icon_pixmap, argv, argc, hints);
2590+}
2591+
2592+int XFree(void *data)
2593+{
2594+ return global_mock->XFree(data);
2595+}
2596+
2597+int XMapWindow(Display *display, Window w)
2598+{
2599+ return global_mock->XMapWindow(display, w);
2600+}
2601+
2602+int XDestroyWindow(Display *display, Window w)
2603+{
2604+ return global_mock->XDestroyWindow(display, w);
2605+}
2606+
2607+int XConnectionNumber(Display *display)
2608+{
2609+ return global_mock->XConnectionNumber(display);
2610+}
2611+
2612+int XNextEvent(Display *display, XEvent *event_return)
2613+{
2614+ return global_mock->XNextEvent(display, event_return);
2615+}
2616+
2617+int XLookupString(XKeyEvent *event_struct, char *buffer_return, int bytes_buffer, KeySym *keysym_return, XComposeStatus *status_in_out)
2618+{
2619+ return global_mock->XLookupString(event_struct, buffer_return, bytes_buffer, keysym_return, status_in_out);
2620+}
2621+
2622+int XRefreshKeyboardMapping(XMappingEvent *event_map)
2623+{
2624+ return global_mock->XRefreshKeyboardMapping(event_map);
2625+}
2626+
2627+Window XDefaultRootWindow(Display *display)
2628+{
2629+ return global_mock->XDefaultRootWindow(display);
2630+}
2631
2632=== modified file 'tests/mir_test_doubles/platform_factory.cpp'
2633--- tests/mir_test_doubles/platform_factory.cpp 2015-06-25 21:34:27 +0000
2634+++ tests/mir_test_doubles/platform_factory.cpp 2015-07-22 20:26:39 +0000
2635@@ -22,6 +22,8 @@
2636
2637 #ifdef MESA_KMS
2638 #include "src/platforms/mesa/server/kms/platform.h"
2639+#elif MESA_X11
2640+#include "src/platforms/mesa/server/x11/platform.h"
2641 #endif
2642
2643 #include "src/server/report/null_report_factory.h"
2644@@ -41,7 +43,7 @@
2645 report::null_display_report());
2646 }
2647
2648-#else
2649+#elif MESA_KMS
2650 auto mtd::create_platform_with_null_dependencies()
2651 -> std::shared_ptr<graphics::Platform>
2652 {
2653@@ -57,4 +59,10 @@
2654 *std::make_shared<NullEmergencyCleanup>(),
2655 graphics::mesa::BypassOption::allowed);
2656 }
2657+#elif MESA_X11
2658+auto mtd::create_platform_with_null_dependencies()
2659+ -> std::shared_ptr<graphics::Platform>
2660+{
2661+ return std::make_shared<graphics::X::Platform>();
2662+}
2663 #endif
2664
2665=== modified file 'tests/mir_test_doubles/stub_buffer.cpp'
2666--- tests/mir_test_doubles/stub_buffer.cpp 2015-06-25 21:34:27 +0000
2667+++ tests/mir_test_doubles/stub_buffer.cpp 2015-07-22 20:26:39 +0000
2668@@ -20,7 +20,7 @@
2669
2670 #ifdef ANDROID
2671 #include "mir/test/doubles/stub_android_native_buffer.h"
2672-#else
2673+#elif defined(MESA_KMS) || defined(MESA_X11)
2674 #include "mir/test/doubles/stub_gbm_native_buffer.h"
2675 #endif
2676
2677@@ -29,9 +29,9 @@
2678 auto mtd::StubBuffer::create_native_buffer()
2679 -> std::shared_ptr<graphics::NativeBuffer>
2680 {
2681-#ifdef MESA_KMS
2682+#if defined(MESA_KMS) || defined(MESA_X11)
2683 return std::make_shared<StubGBMNativeBuffer>(geometry::Size{0,0});
2684-#else
2685+#elif ANDROID
2686 return std::make_shared<StubAndroidNativeBuffer>();
2687 #endif
2688 }
2689
2690=== modified file 'tests/mir_test_framework/stubbed_graphics_platform.cpp'
2691--- tests/mir_test_framework/stubbed_graphics_platform.cpp 2015-07-16 07:03:19 +0000
2692+++ tests/mir_test_framework/stubbed_graphics_platform.cpp 2015-07-22 20:26:39 +0000
2693@@ -65,7 +65,7 @@
2694
2695 std::shared_ptr<mg::NativeBuffer> native_buffer_handle() const override
2696 {
2697-#ifdef MESA_KMS
2698+#if defined(MESA_KMS) || defined(MESA_X11)
2699 auto native_buffer = std::make_shared<mg::NativeBuffer>();
2700 native_buffer->data_items = 1;
2701 native_buffer->data[0] = 0xDEADBEEF;
2702@@ -124,7 +124,7 @@
2703 {
2704 if (msg_type == mg::BufferIpcMsgType::full_msg)
2705 {
2706-#ifdef MESA_KMS
2707+#if defined(MESA_KMS) || defined(MESA_X11)
2708 auto native_handle = buffer.native_buffer_handle();
2709 for(auto i=0; i<native_handle->data_items; i++)
2710 {
2711
2712=== modified file 'tests/unit-tests/CMakeLists.txt'
2713--- tests/unit-tests/CMakeLists.txt 2015-07-14 07:28:55 +0000
2714+++ tests/unit-tests/CMakeLists.txt 2015-07-22 20:26:39 +0000
2715@@ -23,6 +23,7 @@
2716 ${PROJECT_SOURCE_DIR}/src/include/client
2717 ${PROJECT_SOURCE_DIR}/src/include/common
2718 ${PROJECT_SOURCE_DIR}/src/platforms/common/client
2719+ ${PROJECT_SOURCE_DIR}/src/platforms/mesa/server/common
2720 ${GLIB_INCLUDE_DIRS}
2721 )
2722
2723@@ -61,6 +62,12 @@
2724 test_module_deleter.cpp
2725 )
2726
2727+if (MIR_TEST_PLATFORM STREQUAL "mesa-x11")
2728+list(APPEND UNIT_TEST_SOURCES
2729+ $<TARGET_OBJECTS:mirplatformservermesax11objects>
2730+)
2731+endif()
2732+
2733 add_subdirectory(options/)
2734 add_subdirectory(client/)
2735 add_subdirectory(compositor/)
2736@@ -133,11 +140,10 @@
2737 ${XKBCOMMON_LIBRARIES}
2738 )
2739
2740-if (MIR_BUILD_PLATFORM_MESA_KMS)
2741 target_link_libraries(mir_unit_tests
2742 mirsharedmesaservercommon-static
2743+ ${DRM_LDFLAGS} ${DRM_LIBRARIES}
2744 )
2745-endif()
2746
2747 if (MIR_BUILD_PLATFORM_ANDROID)
2748 target_link_libraries(mir_unit_tests
2749
2750=== modified file 'tests/unit-tests/client/CMakeLists.txt'
2751--- tests/unit-tests/client/CMakeLists.txt 2015-07-16 07:03:19 +0000
2752+++ tests/unit-tests/client/CMakeLists.txt 2015-07-22 20:26:39 +0000
2753@@ -23,7 +23,7 @@
2754 add_subdirectory("android")
2755 endif()
2756
2757-if(MIR_TEST_PLATFORM STREQUAL "mesa-kms")
2758+if(MIR_TEST_PLATFORM STREQUAL "mesa-kms" OR MIR_TEST_PLATFORM STREQUAL "mesa-x11" )
2759 add_subdirectory("mesa")
2760 endif()
2761
2762
2763=== modified file 'tests/unit-tests/graphics/CMakeLists.txt'
2764--- tests/unit-tests/graphics/CMakeLists.txt 2015-06-18 02:46:16 +0000
2765+++ tests/unit-tests/graphics/CMakeLists.txt 2015-07-22 20:26:39 +0000
2766@@ -1,9 +1,7 @@
2767 list(APPEND UNIT_TEST_SOURCES
2768- ${CMAKE_CURRENT_SOURCE_DIR}/test_graphics_platform.cpp
2769 ${CMAKE_CURRENT_SOURCE_DIR}/test_display_configuration.cpp
2770 ${CMAKE_CURRENT_SOURCE_DIR}/test_egl_extensions.cpp
2771 ${CMAKE_CURRENT_SOURCE_DIR}/test_egl_error.cpp
2772- ${CMAKE_CURRENT_SOURCE_DIR}/test_display.cpp
2773 ${CMAKE_CURRENT_SOURCE_DIR}/test_default_display_configuration_policy.cpp
2774 ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_id.cpp
2775 ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_properties.cpp
2776@@ -15,16 +13,23 @@
2777 ${CMAKE_CURRENT_SOURCE_DIR}/test_software_cursor.cpp
2778 )
2779
2780+if (MIR_TEST_PLATFORM STREQUAL "mesa-kms" OR MIR_TEST_PLATFORM STREQUAL "android")
2781+ list(APPEND UNIT_TEST_SOURCES
2782+ ${CMAKE_CURRENT_SOURCE_DIR}/test_graphics_platform.cpp
2783+ ${CMAKE_CURRENT_SOURCE_DIR}/test_display.cpp
2784+ )
2785+endif()
2786+
2787 add_subdirectory(nested/)
2788 add_subdirectory(offscreen/)
2789
2790 add_subdirectory(egl_mock/)
2791 if (MIR_TEST_PLATFORM STREQUAL "android")
2792-add_subdirectory(android/)
2793+ add_subdirectory(android/)
2794 endif()
2795
2796-if (MIR_TEST_PLATFORM STREQUAL "mesa-kms")
2797-add_subdirectory(mesa/)
2798+if (MIR_TEST_PLATFORM STREQUAL "mesa-kms" OR MIR_TEST_PLATFORM STREQUAL "mesa-x11")
2799+ add_subdirectory(mesa/)
2800 endif()
2801
2802 set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE)
2803
2804=== modified file 'tests/unit-tests/graphics/mesa/CMakeLists.txt'
2805--- tests/unit-tests/graphics/mesa/CMakeLists.txt 2015-06-19 01:35:28 +0000
2806+++ tests/unit-tests/graphics/mesa/CMakeLists.txt 2015-07-22 20:26:39 +0000
2807@@ -9,4 +9,8 @@
2808 add_subdirectory(kms/)
2809 endif()
2810
2811+if (MIR_TEST_PLATFORM STREQUAL "mesa-x11")
2812+ add_subdirectory(x11/)
2813+endif()
2814+
2815 set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE)
2816
2817=== modified file 'tests/unit-tests/graphics/mesa/common/CMakeLists.txt'
2818--- tests/unit-tests/graphics/mesa/common/CMakeLists.txt 2015-06-18 10:00:46 +0000
2819+++ tests/unit-tests/graphics/mesa/common/CMakeLists.txt 2015-07-22 20:26:39 +0000
2820@@ -1,6 +1,4 @@
2821 add_library(unit_test_graphics_mesa_common OBJECT
2822- ${CMAKE_CURRENT_SOURCE_DIR}/test_gbm_buffer.cpp
2823- ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_allocator.cpp
2824 ${CMAKE_CURRENT_SOURCE_DIR}/test_anonymous_shm_file.cpp
2825 ${CMAKE_CURRENT_SOURCE_DIR}/test_shm_buffer.cpp
2826 ${CMAKE_CURRENT_SOURCE_DIR}/test_drm_helper.cpp
2827
2828=== modified file 'tests/unit-tests/graphics/mesa/common/test_drm_helper.cpp'
2829--- tests/unit-tests/graphics/mesa/common/test_drm_helper.cpp 2015-06-26 08:00:59 +0000
2830+++ tests/unit-tests/graphics/mesa/common/test_drm_helper.cpp 2015-07-22 20:26:39 +0000
2831@@ -50,7 +50,7 @@
2832 protected:
2833 ::testing::NiceMock<mtd::MockDRM> mock_drm;
2834 mtf::UdevEnvironment fake_devices;
2835- mgm::helpers::DRMHelper drm_helper;
2836+ mgm::helpers::DRMHelper drm_helper{mgm::helpers::DRMNodeToUse::card};
2837 };
2838
2839 }
2840
2841=== modified file 'tests/unit-tests/graphics/mesa/kms/CMakeLists.txt'
2842--- tests/unit-tests/graphics/mesa/kms/CMakeLists.txt 2015-06-18 10:00:46 +0000
2843+++ tests/unit-tests/graphics/mesa/kms/CMakeLists.txt 2015-07-22 20:26:39 +0000
2844@@ -1,4 +1,6 @@
2845 add_library(unit_test_graphics_mesa_kms OBJECT
2846+ ${CMAKE_CURRENT_SOURCE_DIR}/test_gbm_buffer.cpp
2847+ ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_allocator.cpp
2848 ${CMAKE_CURRENT_SOURCE_DIR}/test_platform.cpp
2849 ${CMAKE_CURRENT_SOURCE_DIR}/test_display.cpp
2850 ${CMAKE_CURRENT_SOURCE_DIR}/test_display_buffer.cpp
2851
2852=== renamed file 'tests/unit-tests/graphics/mesa/common/test_buffer_allocator.cpp' => 'tests/unit-tests/graphics/mesa/kms/test_buffer_allocator.cpp'
2853--- tests/unit-tests/graphics/mesa/common/test_buffer_allocator.cpp 2015-07-21 04:11:10 +0000
2854+++ tests/unit-tests/graphics/mesa/kms/test_buffer_allocator.cpp 2015-07-22 20:26:39 +0000
2855@@ -63,7 +63,7 @@
2856
2857 platform = mtd::create_mesa_platform_with_null_dependencies();
2858 allocator.reset(new mgm::BufferAllocator(
2859- platform->gbm.device, mgm::BypassOption::allowed));
2860+ platform->gbm.device, mgm::BypassOption::allowed, mgm::BufferImportMethod::gbm_native_pixmap));
2861 }
2862
2863 // Defaults
2864@@ -145,7 +145,8 @@
2865
2866 mgm::BufferAllocator alloc(
2867 platform->gbm.device,
2868- mgm::BypassOption::prohibited);
2869+ mgm::BypassOption::prohibited,
2870+ mgm::BufferImportMethod::gbm_native_pixmap);
2871 auto buf = alloc.alloc_buffer(properties);
2872 ASSERT_TRUE(buf.get() != NULL);
2873 EXPECT_FALSE(buf->native_buffer_handle()->flags & mir_buffer_flag_can_scanout);
2874
2875=== renamed file 'tests/unit-tests/graphics/mesa/common/test_gbm_buffer.cpp' => 'tests/unit-tests/graphics/mesa/kms/test_gbm_buffer.cpp'
2876--- tests/unit-tests/graphics/mesa/common/test_gbm_buffer.cpp 2015-06-26 08:00:59 +0000
2877+++ tests/unit-tests/graphics/mesa/kms/test_gbm_buffer.cpp 2015-07-22 20:26:39 +0000
2878@@ -72,7 +72,7 @@
2879
2880 platform = mtd::create_mesa_platform_with_null_dependencies();
2881
2882- allocator.reset(new mgm::BufferAllocator(platform->gbm.device, mgm::BypassOption::allowed));
2883+ allocator.reset(new mgm::BufferAllocator(platform->gbm.device, mgm::BypassOption::allowed, mgm::BufferImportMethod::gbm_native_pixmap));
2884 }
2885
2886 ::testing::NiceMock<mtd::MockDRM> mock_drm;
2887
2888=== added directory 'tests/unit-tests/graphics/mesa/x11'
2889=== added file 'tests/unit-tests/graphics/mesa/x11/CMakeLists.txt'
2890--- tests/unit-tests/graphics/mesa/x11/CMakeLists.txt 1970-01-01 00:00:00 +0000
2891+++ tests/unit-tests/graphics/mesa/x11/CMakeLists.txt 2015-07-22 20:26:39 +0000
2892@@ -0,0 +1,6 @@
2893+list(APPEND UNIT_TEST_SOURCES
2894+ ${CMAKE_CURRENT_SOURCE_DIR}/test_platform.cpp
2895+ ${CMAKE_CURRENT_SOURCE_DIR}/test_display.cpp
2896+)
2897+
2898+set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE)
2899
2900=== added file 'tests/unit-tests/graphics/mesa/x11/test_display.cpp'
2901--- tests/unit-tests/graphics/mesa/x11/test_display.cpp 1970-01-01 00:00:00 +0000
2902+++ tests/unit-tests/graphics/mesa/x11/test_display.cpp 2015-07-22 20:26:39 +0000
2903@@ -0,0 +1,101 @@
2904+/*
2905+ * Copyright © 2015 Canonical Ltd.
2906+ *
2907+ * This program is free software: you can redistribute it and/or modify
2908+ * it under the terms of the GNU General Public License version 3 as
2909+ * published by the Free Software Foundation.
2910+ *
2911+ * This program is distributed in the hope that it will be useful,
2912+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2913+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2914+ * GNU General Public License for more details.
2915+ *
2916+ * You should have received a copy of the GNU General Public License
2917+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2918+ *
2919+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
2920+ */
2921+#include "src/platforms/mesa/server/x11/display.h"
2922+#include "mir/test/doubles/mock_egl.h"
2923+#include "mir/test/doubles/mock_x11.h"
2924+
2925+#include <gtest/gtest.h>
2926+#include <gmock/gmock.h>
2927+
2928+namespace mg=mir::graphics;
2929+namespace mgx=mg::X;
2930+namespace mtd=mir::test::doubles;
2931+
2932+namespace
2933+{
2934+
2935+EGLint const window_width = 1280;
2936+EGLint const window_height = 1024;
2937+
2938+class X11DisplayTest : public ::testing::Test
2939+{
2940+public:
2941+
2942+ X11DisplayTest()
2943+ {
2944+ using namespace testing;
2945+ EGLint const client_version = 2;
2946+
2947+ ON_CALL(mock_egl, eglQueryContext(mock_egl.fake_egl_display,
2948+ mock_egl.fake_egl_context,
2949+ EGL_CONTEXT_CLIENT_VERSION,
2950+ _))
2951+ .WillByDefault(DoAll(SetArgPointee<3>(client_version),
2952+ Return(EGL_TRUE)));
2953+
2954+ ON_CALL(mock_egl, eglQuerySurface(mock_egl.fake_egl_display,
2955+ mock_egl.fake_egl_surface,
2956+ EGL_WIDTH,
2957+ _))
2958+ .WillByDefault(DoAll(SetArgPointee<3>(window_width),
2959+ Return(EGL_TRUE)));
2960+
2961+ ON_CALL(mock_egl, eglQuerySurface(mock_egl.fake_egl_display,
2962+ mock_egl.fake_egl_surface,
2963+ EGL_HEIGHT,
2964+ _))
2965+ .WillByDefault(DoAll(SetArgPointee<3>(window_height),
2966+ Return(EGL_TRUE)));
2967+
2968+ ON_CALL(mock_egl, eglGetConfigAttrib(mock_egl.fake_egl_display,
2969+ _,
2970+ _,
2971+ _))
2972+ .WillByDefault(DoAll(SetArgPointee<3>(EGL_WINDOW_BIT),
2973+ Return(EGL_TRUE)));
2974+ }
2975+
2976+ std::shared_ptr<mgx::Display> create_display()
2977+ {
2978+ return std::make_shared<mgx::Display>(mock_x11.fake_x11.display);
2979+ }
2980+
2981+ ::testing::NiceMock<mtd::MockEGL> mock_egl;
2982+ ::testing::NiceMock<mtd::MockX11> mock_x11;
2983+};
2984+
2985+}
2986+
2987+TEST_F(X11DisplayTest, creates_display_successfully)
2988+{
2989+ using namespace testing;
2990+
2991+ EXPECT_CALL(mock_egl, eglGetDisplay(mock_x11.fake_x11.display))
2992+ .Times(Exactly(1));
2993+
2994+ EXPECT_CALL(mock_x11, XCreateWindow_wrapper(mock_x11.fake_x11.display,_, window_width, window_height,_,_,_,_,_,_))
2995+ .Times(Exactly(1));
2996+
2997+ EXPECT_CALL(mock_egl, eglCreateContext(mock_egl.fake_egl_display,_, EGL_NO_CONTEXT,_))
2998+ .Times(Exactly(1));
2999+
3000+ EXPECT_CALL(mock_egl, eglCreateWindowSurface(mock_egl.fake_egl_display,_, mock_x11.fake_x11.window, nullptr))
3001+ .Times(Exactly(1));
3002+
3003+ auto display = create_display();
3004+}
3005
3006=== added file 'tests/unit-tests/graphics/mesa/x11/test_platform.cpp'
3007--- tests/unit-tests/graphics/mesa/x11/test_platform.cpp 1970-01-01 00:00:00 +0000
3008+++ tests/unit-tests/graphics/mesa/x11/test_platform.cpp 2015-07-22 20:26:39 +0000
3009@@ -0,0 +1,125 @@
3010+/*
3011+ * Copyright © 2015 Canonical Ltd.
3012+ *
3013+ * This program is free software: you can redistribute it and/or modify
3014+ * it under the terms of the GNU General Public License version 3 as
3015+ * published by the Free Software Foundation.
3016+ *
3017+ * This program is distributed in the hope that it will be useful,
3018+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3019+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3020+ * GNU General Public License for more details.
3021+ *
3022+ * You should have received a copy of the GNU General Public License
3023+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3024+ *
3025+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
3026+ */
3027+
3028+#include "mir/options/program_option.h"
3029+#include "src/platforms/mesa/server/x11/platform.h"
3030+
3031+#include "mir/test/doubles/platform_factory.h"
3032+#include "mir/test/doubles/mock_drm.h"
3033+#include "mir/test/doubles/mock_gbm.h"
3034+#include "mir/test/doubles/mock_x11.h"
3035+#include "mir/shared_library.h"
3036+#include "mir_test_framework/executable_path.h"
3037+#include "mir_test_framework/udev_environment.h"
3038+
3039+#include <gtest/gtest.h>
3040+#include <gmock/gmock.h>
3041+
3042+namespace mg = mir::graphics;
3043+namespace mtd = mir::test::doubles;
3044+namespace mtf = mir_test_framework;
3045+
3046+namespace
3047+{
3048+const char probe_platform[] = "probe_graphics_platform";
3049+
3050+class X11GraphicsPlatformTest : public ::testing::Test
3051+{
3052+public:
3053+ void SetUp()
3054+ {
3055+ ::testing::Mock::VerifyAndClearExpectations(&mock_drm);
3056+ ::testing::Mock::VerifyAndClearExpectations(&mock_gbm);
3057+ }
3058+
3059+ std::shared_ptr<mg::Platform> create_platform()
3060+ {
3061+ return mtd::create_platform_with_null_dependencies();
3062+ }
3063+
3064+ ::testing::NiceMock<mtd::MockDRM> mock_drm;
3065+ ::testing::NiceMock<mtd::MockGBM> mock_gbm;
3066+ ::testing::NiceMock<mtd::MockX11> mock_x11;
3067+};
3068+}
3069+
3070+TEST_F(X11GraphicsPlatformTest, failure_to_open_x11_display_results_in_an_error)
3071+{
3072+ using namespace ::testing;
3073+
3074+ EXPECT_CALL(mock_x11, XOpenDisplay(_))
3075+ .WillRepeatedly(Return(nullptr));
3076+
3077+ EXPECT_THROW({ create_platform(); }, std::exception);
3078+}
3079+
3080+TEST_F(X11GraphicsPlatformTest, failure_to_open_drm_results_in_an_error)
3081+{
3082+ using namespace ::testing;
3083+
3084+ EXPECT_CALL(mock_drm, open(_,_,_))
3085+ .WillRepeatedly(Return(-1));
3086+
3087+ EXPECT_THROW({ create_platform(); }, std::exception);
3088+}
3089+
3090+TEST_F(X11GraphicsPlatformTest, failure_to_create_gbm_device_results_in_an_error)
3091+{
3092+ using namespace ::testing;
3093+
3094+ EXPECT_CALL(mock_gbm, gbm_create_device(mock_drm.fake_drm.fd()))
3095+ .WillRepeatedly(Return(nullptr));
3096+
3097+ EXPECT_THROW({ create_platform(); }, std::exception);
3098+}
3099+
3100+TEST_F(X11GraphicsPlatformTest, probe_returns_unsupported_when_no_drm_udev_devices)
3101+{
3102+ mtf::UdevEnvironment udev_environment;
3103+ mir::options::ProgramOption options;
3104+
3105+ mir::SharedLibrary platform_lib{mtf::server_platform("server-mesa-x11")};
3106+ auto probe = platform_lib.load_function<mg::PlatformProbe>(probe_platform);
3107+ EXPECT_EQ(mg::PlatformPriority::unsupported, probe(options));
3108+}
3109+
3110+TEST_F(X11GraphicsPlatformTest, probe_returns_unsupported_when_x_cannot_open_display)
3111+{
3112+ using namespace ::testing;
3113+
3114+ mir::options::ProgramOption options;
3115+
3116+ EXPECT_CALL(mock_x11, XOpenDisplay(_))
3117+ .WillRepeatedly(Return(nullptr));
3118+
3119+ mir::SharedLibrary platform_lib{mtf::server_platform("server-mesa-x11")};
3120+ auto probe = platform_lib.load_function<mg::PlatformProbe>(probe_platform);
3121+ EXPECT_EQ(mg::PlatformPriority::unsupported, probe(options));
3122+}
3123+
3124+TEST_F(X11GraphicsPlatformTest, probe_returns_best_when_drm_render_nodes_exist)
3125+{
3126+ mtf::UdevEnvironment udev_environment;
3127+ mir::options::ProgramOption options;
3128+
3129+ udev_environment.add_standard_device("standard-drm-render-nodes");
3130+
3131+ mir::SharedLibrary platform_lib{mtf::server_platform("server-mesa-x11")};
3132+ auto probe = platform_lib.load_function<mg::PlatformProbe>(probe_platform);
3133+ EXPECT_EQ(mg::PlatformPriority::best, probe(options));
3134+}
3135
3136=== modified file 'tests/unit-tests/input/CMakeLists.txt'
3137--- tests/unit-tests/input/CMakeLists.txt 2015-06-30 23:23:17 +0000
3138+++ tests/unit-tests/input/CMakeLists.txt 2015-07-22 20:26:39 +0000
3139@@ -15,6 +15,12 @@
3140 ${CMAKE_CURRENT_SOURCE_DIR}/test_validator.cpp
3141 )
3142
3143+if (MIR_TEST_PLATFORM STREQUAL "mesa-x11")
3144+ list(APPEND UNIT_TEST_SOURCES
3145+ ${CMAKE_CURRENT_SOURCE_DIR}/test_x11_dispatchable.cpp
3146+ )
3147+endif()
3148+
3149 set(
3150 UNIT_TEST_SOURCES
3151 ${UNIT_TEST_SOURCES}
3152
3153=== added file 'tests/unit-tests/input/test_x11_dispatchable.cpp'
3154--- tests/unit-tests/input/test_x11_dispatchable.cpp 1970-01-01 00:00:00 +0000
3155+++ tests/unit-tests/input/test_x11_dispatchable.cpp 2015-07-22 20:26:39 +0000
3156@@ -0,0 +1,68 @@
3157+/*
3158+ * Copyright © 2015 Canonical Ltd.
3159+ *
3160+ * This program is free software: you can redistribute it and/or modify
3161+ * it under the terms of the GNU General Public License version 3 as
3162+ * published by the Free Software Foundation.
3163+ *
3164+ * This program is distributed in the hope that it will be useful,
3165+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3166+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3167+ * GNU General Public License for more details.
3168+ *
3169+ * You should have received a copy of the GNU General Public License
3170+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3171+ *
3172+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
3173+ */
3174+
3175+#include "mir/events/event_private.h"
3176+#include "mir_toolkit/event.h"
3177+#include "src/platforms/mesa/server/x11/input/dispatchable.h"
3178+#include "src/platforms/mesa/server/x11/xserver_connection.h"
3179+#include "mir/test/doubles/mock_input_sink.h"
3180+#include "mir/test/doubles/mock_x11.h"
3181+
3182+#include <gtest/gtest.h>
3183+#include <gmock/gmock.h>
3184+
3185+namespace mtd = mir::test::doubles;
3186+
3187+using namespace ::testing;
3188+
3189+extern std::shared_ptr<mir::X::X11Connection> x11_connection;
3190+
3191+namespace
3192+{
3193+
3194+struct X11DispatchableTest : ::testing::Test
3195+{
3196+ X11DispatchableTest()
3197+ {
3198+ // X11Connection freed in the (external) shared_ptr destruction.
3199+ x11_connection.reset(new mir::X::X11Connection());
3200+ }
3201+
3202+ ~X11DispatchableTest()
3203+ {
3204+ x11_connection.reset();
3205+ }
3206+
3207+ mir::input::X::XDispatchable x11_dispatchable{0};
3208+ NiceMock<mtd::MockInputSink> mock_input_sink;
3209+ NiceMock<mtd::MockX11> mock_x11;
3210+};
3211+
3212+}
3213+
3214+TEST_F(X11DispatchableTest, dispatches_input_events_to_sink)
3215+{
3216+ ON_CALL(mock_x11, XNextEvent(_,_))
3217+ .WillByDefault(DoAll(SetArgPointee<1>(mock_x11.fake_x11.event_return),
3218+ Return(1)));
3219+
3220+ EXPECT_CALL(mock_input_sink, handle_input(_));
3221+
3222+ x11_dispatchable.set_input_sink(&mock_input_sink);
3223+ x11_dispatchable.dispatch(mir::dispatch::FdEvent::readable);
3224+}

Subscribers

People subscribed via source and target branches