Mir

Merge lp:~raof/mir/eglstream-platform into lp:mir

Proposed by Chris Halse Rogers
Status: Merged
Merged at revision: 3537
Proposed branch: lp:~raof/mir/eglstream-platform
Merge into: lp:mir
Diff against target: 2843 lines (+2556/-12)
32 files modified
.bzrignore (+3/-0)
CMakeLists.txt (+9/-2)
include/client/mir_toolkit/client_types.h (+2/-1)
src/platforms/CMakeLists.txt (+5/-1)
src/platforms/eglstream-kms/CMakeLists.txt (+2/-0)
src/platforms/eglstream-kms/client/CMakeLists.txt (+39/-0)
src/platforms/eglstream-kms/client/client_buffer.cpp (+159/-0)
src/platforms/eglstream-kms/client/client_buffer.h (+67/-0)
src/platforms/eglstream-kms/client/client_buffer_factory.cpp (+36/-0)
src/platforms/eglstream-kms/client/client_buffer_factory.h (+45/-0)
src/platforms/eglstream-kms/client/client_platform.cpp (+77/-0)
src/platforms/eglstream-kms/client/client_platform.h (+52/-0)
src/platforms/eglstream-kms/client/client_platform_factory.cpp (+59/-0)
src/platforms/eglstream-kms/client/symbols.map (+7/-0)
src/platforms/eglstream-kms/server/CMakeLists.txt (+55/-0)
src/platforms/eglstream-kms/server/buffer_allocator.cpp (+69/-0)
src/platforms/eglstream-kms/server/buffer_allocator.h (+48/-0)
src/platforms/eglstream-kms/server/display.cpp (+363/-0)
src/platforms/eglstream-kms/server/display.h (+82/-0)
src/platforms/eglstream-kms/server/egl_output.cpp (+359/-0)
src/platforms/eglstream-kms/server/egl_output.h (+79/-0)
src/platforms/eglstream-kms/server/kms_display_configuration.cpp (+331/-0)
src/platforms/eglstream-kms/server/kms_display_configuration.h (+70/-0)
src/platforms/eglstream-kms/server/platform.cpp (+162/-0)
src/platforms/eglstream-kms/server/platform.h (+66/-0)
src/platforms/eglstream-kms/server/platform_symbols.cpp (+189/-0)
src/platforms/eglstream-kms/server/symbols.map.in (+10/-0)
src/platforms/mesa/server/kms/platform_symbols.cpp (+14/-0)
tests/unit-tests/CMakeLists.txt (+4/-0)
tests/unit-tests/client/test_probing_client_platform_factory.cpp (+32/-0)
tests/unit-tests/graphics/mesa/kms/test_platform.cpp (+47/-2)
tests/unit-tests/graphics/test_platform_prober.cpp (+14/-6)
To merge this branch: bzr merge lp:~raof/mir/eglstream-platform
Reviewer Review Type Date Requested Status
Mir CI Bot continuous-integration Needs Fixing
Alan Griffiths Abstain
Cemil Azizoglu (community) Needs Fixing
Daniel van Vugt Pending
Review via email: mp+296389@code.launchpad.net

Commit message

Add an EGLStream client platform and KMS-backed EGLStream server platform.

Currently supports only software clients, as hooking into nvidia's EGL is not (yet?) possible.

Description of the change

The actual EGLStream platform

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3540
https://mir-jenkins.ubuntu.com/job/mir-ci/1082/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/1198
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1248
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1239
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1239
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1208
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1208/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1208
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1208/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1208
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1208/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1208
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1208/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1208
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1208/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1082/rebuild

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

No tests needed?

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

Are there eglstream implementations that don't use kms? Instead of eglstream-kms, can't we call it eglstream?

------------------------
Couldn't mesa-kms and/or mesa-x11 return mg::PlatformPriority::best when eglstream-kms returns that? (unless render nodes and/or dri nodes are unavailable when using eglstream).

2489 +mg::PlatformPriority probe_graphics_platform(mo::ProgramOption const& /*options*/)

------------------------

Are guest platforms a TODO or will they be unsupported forever? A comment would be good either way?

2587 +mir::UniqueModulePtr<mg::Platform> create_guest_platform(
2588 + std::shared_ptr<mg::DisplayReport> const&,
2589 + std::shared_ptr<mg::NestedContext> const& /*nested_context*/)
2590 +{
2591 + mir::assert_entry_point_signature<mg::CreateGuestPlatform>(&create_guest_platform);
2592 + return nullptr;
2593 +}

------------------------
Isn't this going to require root? Can drm render nodes not be used instead?
2238 + if (drmSetMaster(drm_node))

------------------------
Any reason why we don't request alpha? I changed mir-on-X on Gerry's request that he needed alpha. May want to do the same here.
907 + EGL_ALPHA_SIZE, 0,

------------------------
This only supports software rendering but we should still check for
      if (buffer_properties.usage == BufferUsage::software)
and throw if hardware is requested.

765 +std::shared_ptr<mg::Buffer> mge::BufferAllocator::alloc_buffer(
766
------------------------
s/falied/failed
+ "Platform claims to support EGL_EXT_device_base, but eglQueryDevicesEXT falied: %s",

------------------------
Probably be better handled by returning unsupported as was done to get the device_count.
2533 + if (eglQueryDevicesEXT(device_count, devices.get(), &device_count) != EGL_TRUE)
2534 + {
2535 + BOOST_THROW_EXCEPTION(mg::egl_error("Failed to get device list with eglQueryDevicesEXT"));
2536 + }

review: Needs Fixing
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3541
https://mir-jenkins.ubuntu.com/job/mir-ci/1101/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/1220
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1270
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1261
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1261
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1230
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1230/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1230
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1230/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1230
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1230/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1230
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1230/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1230
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1230/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1101/rebuild

review: Approve (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3544
https://mir-jenkins.ubuntu.com/job/mir-ci/1111/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/1230/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1280
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1271
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1271
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1240
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1240/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1240
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1240/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1240
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1240/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1240/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1240
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1240/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1111/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3544
https://mir-jenkins.ubuntu.com/job/mir-ci/1116/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/1235
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1285
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1276
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1276
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1245
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1245/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1245
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1245/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1245
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1245/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1245
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1245/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1245
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1245/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1116/rebuild

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

This seems like a lot of code with only the most trivial of tests. But I guess there's a limit to what we can test when it is supplying our abstraction over the drivers.

review: Abstain
Revision history for this message
Chris Halse Rogers (raof) wrote :

There are some more tests that I could usefully write; I'll write some tests that the platform-probe succeeds in appropriate environments and fails in inappropriate ones.

I'll also investigate writing a dummy KMS driver; that would let us usefully test a whole lot more.

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

We can land wit ha promise of tests later

Revision history for this message
Mir CI Bot (mir-ci-bot) :
review: Approve (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) :
review: Approve (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
https://mir-jenkins.ubuntu.com/job/mir-autolanding/311/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/1265
    FAILURE: https://mir-jenkins.ubuntu.com/job/generic-land-mp/336/console
    None: https://mir-jenkins.ubuntu.com/job/generic-land-mp/337/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1315
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1306
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1306
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1275
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1275/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1275
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1275/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1275
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1275/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1275
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1275/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1275
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1275/artifact/output/*zip*/output.zip

review: Needs Fixing (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

Ahem. Post-merge response to Cemil.

> Are there eglstream implementations that don't use kms? Instead of eglstream-kms, can't we call > it eglstream?

nvidia currently have non-KMS platforms that use EGLStream (they've talked about OpenWF things). We don't currently have non-KMS EGLStream platforms, but they're plausible.

> Couldn't mesa-kms and/or mesa-x11 return mg::PlatformPriority::best when eglstream-kms returns > that? (unless render nodes and/or dri nodes are unavailable when using eglstream).

This was resolved by commits (and tests!) subsequent to this question; mesa-kms now checks for the EGL_MESA_platform_gbm extension (which provides the gbm-import features that we use).

> Are guest platforms a TODO or will they be unsupported forever? A comment would be good either > way?

Guest platforms are a TODO, albeit a TODO that I hope to delay until it no longer needs to be done (splitting output from buffer-allocation will remove guest platforms entirely)

> Isn't this going to require root? Can drm render nodes not be used instead?
> 2238 + if (drmSetMaster(drm_node))

Yes, this requires root (or to already be master, IIRC). You need to be master to do modesetting, so the platform can't work unless it's master.

Render nodes (as their name suggests) can't do modesetting ☺

> Any reason why we don't request alpha? I changed mir-on-X on Gerry's request that he needed
> alpha. May want to do the same here.
> 907 + EGL_ALPHA_SIZE, 0,

Hm, probably. I'll look into this when I get home and can test it.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file '.bzrignore'
--- .bzrignore 1970-01-01 00:00:00 +0000
+++ .bzrignore 2016-06-08 13:28:19 +0000
@@ -0,0 +1,3 @@
1.idea
2build
3include/server/mir/version.h
04
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2016-06-02 05:33:50 +0000
+++ CMakeLists.txt 2016-06-08 13:28:19 +0000
@@ -163,10 +163,10 @@
163# Default to KMS backend, but build all of them163# Default to KMS backend, but build all of them
164set(164set(
165 MIR_PLATFORM165 MIR_PLATFORM
166 mesa-kms;android;mesa-x11166 mesa-kms;android;mesa-x11;eglstream-kms
167 CACHE167 CACHE
168 STRING168 STRING
169 "a list of graphics backends to build (options are 'mesa-kms', 'android' or 'mesa-x11')"169 "a list of graphics backends to build (options are 'mesa-kms', 'android', 'mesa-x11', or 'eglstream-kms')"
170)170)
171171
172list(GET MIR_PLATFORM 0 MIR_TEST_PLATFORM)172list(GET MIR_PLATFORM 0 MIR_TEST_PLATFORM)
@@ -183,6 +183,9 @@
183 if (platform STREQUAL "mesa-x11")183 if (platform STREQUAL "mesa-x11")
184 set(MIR_BUILD_PLATFORM_MESA_X11 TRUE)184 set(MIR_BUILD_PLATFORM_MESA_X11 TRUE)
185 endif()185 endif()
186 if (platform STREQUAL "eglstream-kms")
187 set(MIR_BUILD_PLATFORM_EGLSTREAM_KMS TRUE)
188 endif()
186endforeach(platform)189endforeach(platform)
187190
188find_package(EGL REQUIRED)191find_package(EGL REQUIRED)
@@ -245,6 +248,10 @@
245 pkg_check_modules( DRM REQUIRED libdrm )248 pkg_check_modules( DRM REQUIRED libdrm )
246endif()249endif()
247250
251if (MIR_BUILD_PLATFORM_EGLSTREAM_KMS)
252 pkg_check_modules(EPOXY REQUIRED epoxy)
253endif()
254
248set(MIR_ANDROID_INCLUDE_DIRECTORIES) # to be filled by android-input255set(MIR_ANDROID_INCLUDE_DIRECTORIES) # to be filled by android-input
249set(MIR_ANDROID_INPUT_COMPILE_FLAGS) # to be filled by android-input256set(MIR_ANDROID_INPUT_COMPILE_FLAGS) # to be filled by android-input
250set(MIR_3RD_PARTY_INCLUDE_DIRECTORIES)257set(MIR_3RD_PARTY_INCLUDE_DIRECTORIES)
251258
=== modified file 'include/client/mir_toolkit/client_types.h'
--- include/client/mir_toolkit/client_types.h 2016-05-03 06:55:25 +0000
+++ include/client/mir_toolkit/client_types.h 2016-06-08 13:28:19 +0000
@@ -200,7 +200,8 @@
200typedef enum MirPlatformType200typedef enum MirPlatformType
201{201{
202 mir_platform_type_gbm,202 mir_platform_type_gbm,
203 mir_platform_type_android203 mir_platform_type_android,
204 mir_platform_type_eglstream,
204} MirPlatformType;205} MirPlatformType;
205206
206typedef struct MirPlatformPackage207typedef struct MirPlatformPackage
207208
=== modified file 'src/platforms/CMakeLists.txt'
--- src/platforms/CMakeLists.txt 2016-05-03 06:55:25 +0000
+++ src/platforms/CMakeLists.txt 2016-06-08 13:28:19 +0000
@@ -71,4 +71,8 @@
71 add_subdirectory(android/)71 add_subdirectory(android/)
72endif()72endif()
7373
74 add_subdirectory(evdev/)74if (MIR_BUILD_PLATFORM_EGLSTREAM_KMS)
75 add_subdirectory(eglstream-kms)
76endif()
77
78add_subdirectory(evdev/)
7579
=== added directory 'src/platforms/eglstream-kms'
=== added file 'src/platforms/eglstream-kms/CMakeLists.txt'
--- src/platforms/eglstream-kms/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/CMakeLists.txt 2016-06-08 13:28:19 +0000
@@ -0,0 +1,2 @@
1add_subdirectory(client/)
2add_subdirectory(server/)
03
=== added directory 'src/platforms/eglstream-kms/client'
=== added file 'src/platforms/eglstream-kms/client/CMakeLists.txt'
--- src/platforms/eglstream-kms/client/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/client/CMakeLists.txt 2016-06-08 13:28:19 +0000
@@ -0,0 +1,39 @@
1include_directories(${client_common_include_dirs})
2
3include_directories(
4 ${DRM_INCLUDE_DIRS}
5 ${EGL_INCLUDE_DIRS}
6)
7
8set(symbol_map ${CMAKE_CURRENT_SOURCE_DIR}/symbols.map)
9
10add_library(mirclientplatformeglstreamobjects OBJECT
11 client_platform_factory.cpp
12 client_platform.cpp
13 client_buffer_factory.cpp
14 client_buffer.cpp
15)
16
17mir_add_library_with_symbols(
18 mirclientplatformeglstream MODULE
19
20 ${symbol_map}
21 $<TARGET_OBJECTS:mirclientplatformeglstreamobjects>
22)
23
24set_target_properties(
25 mirclientplatformeglstream PROPERTIES
26 OUTPUT_NAME eglstream
27 LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/client-modules
28 PREFIX ""
29 SUFFIX ".so.${MIR_CLIENT_PLATFORM_ABI}"
30 LINK_FLAGS "-Wl,--version-script,${symbol_map}"
31)
32
33target_link_libraries(mirclientplatformeglstream
34 mirclient
35 client_platform_common
36 ${DRM_LDFLAGS} ${DRM_LIBRARIES}
37)
38
39install(TARGETS mirclientplatformeglstream LIBRARY DESTINATION ${MIR_CLIENT_PLATFORM_PATH})
040
=== added file 'src/platforms/eglstream-kms/client/client_buffer.cpp'
--- src/platforms/eglstream-kms/client/client_buffer.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/client/client_buffer.cpp 2016-06-08 13:28:19 +0000
@@ -0,0 +1,159 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#include "mir_toolkit/mir_client_library.h"
20#include "client_buffer.h"
21
22#include <boost/throw_exception.hpp>
23
24#include <stdexcept>
25#include <system_error>
26
27#include <errno.h>
28#include <sys/mman.h>
29
30namespace mcl=mir::client;
31namespace mcle=mir::client::eglstream;
32namespace geom=mir::geometry;
33
34namespace
35{
36
37struct ShmMemoryRegion : mcl::MemoryRegion
38{
39 ShmMemoryRegion(
40 int buffer_fd,
41 geom::Size const& size_param,
42 geom::Stride stride_param,
43 MirPixelFormat format_param)
44 : size_in_bytes{size_param.height.as_uint32_t() * stride_param.as_uint32_t()}
45 {
46 static off_t const map_offset = 0;
47 width = size_param.width;
48 height = size_param.height;
49 stride = stride_param;
50 format = format_param;
51
52 void* map = mmap(
53 nullptr,
54 size_in_bytes,
55 PROT_READ | PROT_WRITE,
56 MAP_SHARED,
57 buffer_fd,
58 map_offset);
59 if (map == MAP_FAILED)
60 {
61 BOOST_THROW_EXCEPTION((
62 std::system_error{errno, std::system_category(), "Failed to mmap buffer"}));
63 }
64
65 vaddr = std::shared_ptr<char>(static_cast<char*>(map), [](auto*) noexcept {});
66 }
67
68 ~ShmMemoryRegion()
69 {
70 munmap(vaddr.get(), size_in_bytes);
71 }
72
73 size_t const size_in_bytes;
74};
75
76}
77
78mcle::ClientBuffer::ClientBuffer(
79 std::shared_ptr<MirBufferPackage> const& package,
80 geom::Size size, MirPixelFormat pf)
81 : creation_package{package},
82 rect({geom::Point{0, 0}, size}),
83 buffer_pf{pf}
84{
85 if (package->fd_items != 1)
86 {
87 BOOST_THROW_EXCEPTION(std::runtime_error(
88 "Buffer package does not contain the expected number of fd items"));
89 }
90}
91
92mcle::ClientBuffer::~ClientBuffer() noexcept
93{
94 // TODO (@raof): Error reporting? It should not be possible for this to fail; if it does,
95 // something's seriously wrong.
96 close(creation_package->fd[0]);
97}
98
99std::shared_ptr<mcl::MemoryRegion> mcle::ClientBuffer::secure_for_cpu_write()
100{
101 int const buffer_fd = creation_package->fd[0];
102
103 return std::make_shared<ShmMemoryRegion>(
104 buffer_fd,
105 size(),
106 stride(),
107 pixel_format());
108}
109
110geom::Size mcle::ClientBuffer::size() const
111{
112 return rect.size;
113}
114
115geom::Stride mcle::ClientBuffer::stride() const
116{
117 return geom::Stride{creation_package->stride};
118}
119
120MirPixelFormat mcle::ClientBuffer::pixel_format() const
121{
122 return buffer_pf;
123}
124
125std::shared_ptr<MirNativeBuffer> mcle::ClientBuffer::native_buffer_handle() const
126{
127 creation_package->age = age();
128 return creation_package;
129}
130
131void mcle::ClientBuffer::update_from(MirBufferPackage const&)
132{
133}
134
135void mcle::ClientBuffer::fill_update_msg(MirBufferPackage& package)
136{
137 package.data_items = 0;
138 package.fd_items = 0;
139}
140
141MirNativeBuffer* mcle::ClientBuffer::as_mir_native_buffer() const
142{
143 //mesa has a POD native type for now. can return it directly to client API.
144 return native_buffer_handle().get();
145}
146
147void mcle::ClientBuffer::set_fence(MirNativeFence*, MirBufferAccess)
148{
149}
150
151MirNativeFence* mcle::ClientBuffer::get_fence() const
152{
153 return nullptr;
154}
155
156bool mcle::ClientBuffer::wait_fence(MirBufferAccess, std::chrono::nanoseconds)
157{
158 return true;
159}
0160
=== added file 'src/platforms/eglstream-kms/client/client_buffer.h'
--- src/platforms/eglstream-kms/client/client_buffer.h 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/client/client_buffer.h 2016-06-08 13:28:19 +0000
@@ -0,0 +1,67 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by:
17 * Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
18 */
19
20#ifndef MIR_CLIENT_EGLSTREAM_CLIENT_BUFFER_H_
21#define MIR_CLIENT_EGLSTREAM_CLIENT_BUFFER_H_
22
23#include "mir/aging_buffer.h"
24#include "mir_toolkit/mir_client_library.h"
25#include "mir/geometry/rectangle.h"
26
27#include <memory>
28
29namespace mir
30{
31namespace client
32{
33namespace eglstream
34{
35
36class ClientBuffer : public AgingBuffer
37{
38public:
39 ClientBuffer(
40 std::shared_ptr<MirBufferPackage> const& buffer_package,
41 geometry::Size size,
42 MirPixelFormat pf);
43
44 ~ClientBuffer() noexcept;
45
46 std::shared_ptr<MemoryRegion> secure_for_cpu_write();
47 geometry::Size size() const;
48 geometry::Stride stride() const;
49 MirPixelFormat pixel_format() const;
50 std::shared_ptr<MirNativeBuffer> native_buffer_handle() const;
51 void update_from(MirBufferPackage const&);
52 void fill_update_msg(MirBufferPackage&);
53 MirNativeBuffer* as_mir_native_buffer() const;
54 void set_fence(MirNativeFence*, MirBufferAccess);
55 MirNativeFence* get_fence() const;
56 bool wait_fence(MirBufferAccess, std::chrono::nanoseconds timeout);
57
58private:
59 std::shared_ptr<MirBufferPackage> const creation_package;
60 geometry::Rectangle const rect;
61 MirPixelFormat const buffer_pf;
62};
63
64}
65}
66}
67#endif /* MIR_CLIENT_EGLSTREAM_CLIENT_BUFFER_H_ */
068
=== added file 'src/platforms/eglstream-kms/client/client_buffer_factory.cpp'
--- src/platforms/eglstream-kms/client/client_buffer_factory.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/client/client_buffer_factory.cpp 2016-06-08 13:28:19 +0000
@@ -0,0 +1,36 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by:
17 * Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
18 */
19
20#include "client_buffer_factory.h"
21#include "client_buffer.h"
22
23namespace mcl=mir::client;
24namespace mcle=mir::client::eglstream;
25
26std::shared_ptr<mcl::ClientBuffer>
27mcle::ClientBufferFactory::create_buffer(
28 std::shared_ptr<MirBufferPackage> const& package,
29 geometry::Size /*size*/,
30 MirPixelFormat pf)
31{
32 return std::make_shared<mcle::ClientBuffer>(
33 package,
34 geometry::Size{package->width, package->height},
35 pf);
36}
037
=== added file 'src/platforms/eglstream-kms/client/client_buffer_factory.h'
--- src/platforms/eglstream-kms/client/client_buffer_factory.h 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/client/client_buffer_factory.h 2016-06-08 13:28:19 +0000
@@ -0,0 +1,45 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by:
17 * Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
18 */
19
20#ifndef MIR_CLIENT_EGLSTREAM_CLIENT_BUFFER_FACTORY_H_
21#define MIR_CLIENT_EGLSTREAM_CLIENT_BUFFER_FACTORY_H_
22
23#include "mir/client_buffer_factory.h"
24
25namespace mir
26{
27namespace client
28{
29namespace eglstream
30{
31
32class ClientBufferFactory : public client::ClientBufferFactory
33{
34public:
35 ClientBufferFactory() = default;
36
37 std::shared_ptr<client::ClientBuffer> create_buffer(
38 std::shared_ptr<MirBufferPackage> const& package,
39 geometry::Size size, MirPixelFormat pf);
40};
41
42}
43}
44}
45#endif /* MIR_CLIENT_EGLSTREAM_CLIENT_BUFFER_FACTORY_H_ */
046
=== added file 'src/platforms/eglstream-kms/client/client_platform.cpp'
--- src/platforms/eglstream-kms/client/client_platform.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/client/client_platform.cpp 2016-06-08 13:28:19 +0000
@@ -0,0 +1,77 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#include "mir_toolkit/mir_client_library.h"
20#include "client_platform.h"
21#include "client_buffer_factory.h"
22#include "mir/client_buffer_factory.h"
23#include "mir/client_context.h"
24
25#include <cstring>
26#include <boost/throw_exception.hpp>
27
28namespace mcl=mir::client;
29namespace mcle=mir::client::eglstream;
30namespace geom=mir::geometry;
31
32mcle::ClientPlatform::ClientPlatform(ClientContext* const context)
33 : context{context}
34{
35}
36
37std::shared_ptr<mcl::ClientBufferFactory> mcle::ClientPlatform::create_buffer_factory()
38{
39 return std::make_shared<mcle::ClientBufferFactory>();
40}
41
42std::shared_ptr<void> mcle::ClientPlatform::create_egl_native_window(EGLNativeSurface* /*client_surface*/)
43{
44 return nullptr;
45}
46
47std::shared_ptr<EGLNativeDisplayType> mcle::ClientPlatform::create_egl_native_display()
48{
49 return nullptr;
50}
51
52MirPlatformType mcle::ClientPlatform::platform_type() const
53{
54 return mir_platform_type_eglstream;
55}
56
57void mcle::ClientPlatform::populate(MirPlatformPackage& /*package*/) const
58{
59}
60
61MirPlatformMessage* mcle::ClientPlatform::platform_operation(MirPlatformMessage const* /*msg*/)
62{
63 return nullptr;
64}
65
66MirNativeBuffer* mcle::ClientPlatform::convert_native_buffer(graphics::NativeBuffer* buf) const
67{
68 // Only buffers we currently support are ShmBuffers, which are type-compatible
69 return buf;
70}
71
72
73MirPixelFormat mcle::ClientPlatform::get_egl_pixel_format(
74 EGLDisplay /*disp*/, EGLConfig /*conf*/) const
75{
76 BOOST_THROW_EXCEPTION(std::runtime_error{"EGL support unimplemented"});
77}
078
=== added file 'src/platforms/eglstream-kms/client/client_platform.h'
--- src/platforms/eglstream-kms/client/client_platform.h 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/client/client_platform.h 2016-06-08 13:28:19 +0000
@@ -0,0 +1,52 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18#ifndef MIR_CLIENT_EGLSTREAM_CLIENT_PLATFORM_H_
19#define MIR_CLIENT_EGLSTREAM_CLIENT_PLATFORM_H_
20
21#include "mir/client_platform.h"
22
23namespace mir
24{
25namespace client
26{
27namespace eglstream
28{
29
30class ClientPlatform : public client::ClientPlatform
31{
32public:
33 ClientPlatform(ClientContext* const context);
34
35 MirPlatformType platform_type() const override;
36 void populate(MirPlatformPackage& package) const override;
37 MirPlatformMessage* platform_operation(MirPlatformMessage const* request) override;
38 std::shared_ptr<ClientBufferFactory> create_buffer_factory() override;
39 std::shared_ptr<void> create_egl_native_window(EGLNativeSurface *surface) override;
40 std::shared_ptr<EGLNativeDisplayType> create_egl_native_display() override;
41 MirNativeBuffer* convert_native_buffer(graphics::NativeBuffer*) const override;
42 MirPixelFormat get_egl_pixel_format(EGLDisplay, EGLConfig) const override;
43
44private:
45 ClientContext* const context;
46};
47
48}
49}
50}
51
52#endif /* MIR_CLIENT_EGLSTREAM_CLIENT_PLATFORM_H_ */
053
=== added file 'src/platforms/eglstream-kms/client/client_platform_factory.cpp'
--- src/platforms/eglstream-kms/client/client_platform_factory.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/client/client_platform_factory.cpp 2016-06-08 13:28:19 +0000
@@ -0,0 +1,59 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#include "mir/client_platform_factory.h"
20#include "client_platform.h"
21#include "mir_toolkit/client_types.h"
22#include "mir/client_context.h"
23#include "mir/egl_native_display_container.h"
24#include "mir/assert_module_entry_point.h"
25#include "mir/module_deleter.h"
26
27#include "mir_toolkit/mir_client_library.h"
28
29#include <cstring>
30
31namespace mcl = mir::client;
32namespace mcle = mcl::eglstream;
33
34namespace
35{
36bool is_eglstream_server(mcl::ClientContext* context)
37{
38 MirModuleProperties module_properties;
39
40 context->populate_graphics_module(module_properties);
41
42 return strncmp(module_properties.name, "mir:eglstream", strlen("mir:eglstream")) == 0;
43}
44}
45
46mir::UniqueModulePtr<mcl::ClientPlatform> create_client_platform(mcl::ClientContext* context)
47{
48 mir::assert_entry_point_signature<mcl::CreateClientPlatform>(&create_client_platform);
49
50 return mir::make_module_ptr<mcle::ClientPlatform>(context);
51}
52
53bool
54is_appropriate_module(mcl::ClientContext* context)
55{
56 mir::assert_entry_point_signature<mcl::ClientPlatformProbe>(&is_appropriate_module);
57
58 return is_eglstream_server(context);
59}
060
=== added file 'src/platforms/eglstream-kms/client/symbols.map'
--- src/platforms/eglstream-kms/client/symbols.map 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/client/symbols.map 2016-06-08 13:28:19 +0000
@@ -0,0 +1,7 @@
1MIR_CLIENT_PLATFORM_5 {
2 global:
3 create_client_platform;
4 is_appropriate_module;
5 local:
6 *;
7};
08
=== added directory 'src/platforms/eglstream-kms/server'
=== added file 'src/platforms/eglstream-kms/server/CMakeLists.txt'
--- src/platforms/eglstream-kms/server/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/server/CMakeLists.txt 2016-06-08 13:28:19 +0000
@@ -0,0 +1,55 @@
1include_directories(
2 ${server_common_include_dirs}
3 ${DRM_INCLUDE_DIRS}
4 ${GBM_INCLUDE_DIRS}
5 ${EGL_INCLUDE_DIRS}
6 ${GLESv2_INCLUDE_DIRS}
7 ${EPOXY_INCLUDE_DIRS}
8)
9
10configure_file(
11 ${CMAKE_CURRENT_SOURCE_DIR}/symbols.map.in
12 ${CMAKE_CURRENT_BINARY_DIR}/symbols.map
13)
14set(symbol_map ${CMAKE_CURRENT_BINARY_DIR}/symbols.map)
15
16mir_add_library_with_symbols(
17 mirplatformgraphicseglstreamkms MODULE
18
19 ${symbol_map}
20 platform_symbols.cpp
21 platform.cpp
22 buffer_allocator.cpp
23 buffer_allocator.h
24 display.cpp
25 display.h
26 kms_display_configuration.h
27 kms_display_configuration.cpp
28 egl_output.h
29 egl_output.cpp
30)
31
32target_link_libraries(
33 mirplatformgraphicseglstreamkms
34
35 PRIVATE
36 mirplatform
37 server_platform_common
38 kms_utils
39 ${Boost_PROGRAM_OPTIONS_LIBRARY}
40 ${DRM_LDFLAGS} ${DRM_LIBRARIES}
41 ${EGL_LDFLAGS} ${EGL_LIBRARIES}
42 ${GLESv2_LDFLAGS} ${GLESv2_LIBRARIES}
43 ${EPOXY_LDFLAGS} ${EPOXY_LIBRARIES}
44)
45
46set_target_properties(
47 mirplatformgraphicseglstreamkms PROPERTIES
48 OUTPUT_NAME graphics-eglstream-kms
49 LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/server-modules
50 PREFIX ""
51 SUFFIX ".so.${MIR_SERVER_GRAPHICS_PLATFORM_ABI}"
52 LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${symbol_map}"
53)
54
55install(TARGETS mirplatformgraphicseglstreamkms LIBRARY DESTINATION ${MIR_SERVER_PLATFORM_PATH})
056
=== added file 'src/platforms/eglstream-kms/server/buffer_allocator.cpp'
--- src/platforms/eglstream-kms/server/buffer_allocator.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/server/buffer_allocator.cpp 2016-06-08 13:28:19 +0000
@@ -0,0 +1,69 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by:
17 * Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
18 */
19
20#include "buffer_allocator.h"
21#include "buffer_texture_binder.h"
22#include "anonymous_shm_file.h"
23#include "shm_buffer.h"
24#include "mir/graphics/buffer_properties.h"
25#include <boost/throw_exception.hpp>
26#include <boost/exception/errinfo_errno.hpp>
27
28#include <system_error>
29#include <cassert>
30
31namespace mg = mir::graphics;
32namespace mge = mg::eglstream;
33namespace mgc = mg::common;
34namespace geom = mir::geometry;
35
36mge::BufferAllocator::BufferAllocator()
37{
38}
39
40std::shared_ptr<mg::Buffer> mge::BufferAllocator::alloc_buffer(
41 BufferProperties const& buffer_properties)
42{
43 if (!mgc::ShmBuffer::supports(buffer_properties.format))
44 {
45 BOOST_THROW_EXCEPTION(
46 std::runtime_error(
47 "Trying to create SHM buffer with unsupported pixel format"));
48 }
49
50 auto const stride = geom::Stride{
51 MIR_BYTES_PER_PIXEL(buffer_properties.format) *
52 buffer_properties.size.width.as_uint32_t()};
53 size_t const size_in_bytes =
54 stride.as_int() * buffer_properties.size.height.as_int();
55 auto shm_file =
56 std::make_unique<mgc::AnonymousShmFile>(size_in_bytes);
57
58 auto const buffer =
59 std::make_shared<mgc::ShmBuffer>(std::move(shm_file), buffer_properties.size,
60 buffer_properties.format);
61
62 return buffer;
63}
64
65std::vector<MirPixelFormat> mge::BufferAllocator::supported_pixel_formats()
66{
67 // Lazy
68 return {mir_pixel_format_argb_8888, mir_pixel_format_xrgb_8888};
69}
070
=== added file 'src/platforms/eglstream-kms/server/buffer_allocator.h'
--- src/platforms/eglstream-kms/server/buffer_allocator.h 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/server/buffer_allocator.h 2016-06-08 13:28:19 +0000
@@ -0,0 +1,48 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#ifndef MIR_PLATFORMS_EGLSTREAM_BUFFER_ALLOCATOR_
20#define MIR_PLATFORMS_EGLSTREAM_BUFFER_ALLOCATOR_
21
22#include "mir/graphics/graphic_buffer_allocator.h"
23#include "mir/graphics/buffer_id.h"
24
25#include <memory>
26
27namespace mir
28{
29namespace graphics
30{
31
32namespace eglstream
33{
34
35class BufferAllocator: public graphics::GraphicBufferAllocator
36{
37public:
38 BufferAllocator();
39
40 std::shared_ptr<Buffer> alloc_buffer(graphics::BufferProperties const& buffer_properties) override;
41 std::vector<MirPixelFormat> supported_pixel_formats() override;
42};
43
44}
45}
46}
47
48#endif // MIR_PLATFORMS_EGLSTREAM_BUFFER_ALLOCATOR_
049
=== added file 'src/platforms/eglstream-kms/server/display.cpp'
--- src/platforms/eglstream-kms/server/display.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/server/display.cpp 2016-06-08 13:28:19 +0000
@@ -0,0 +1,363 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#include <epoxy/egl.h>
20
21#include "display.h"
22#include "egl_output.h"
23
24#include "kms-utils/drm_mode_resources.h"
25
26#include "mir/graphics/display_configuration.h"
27#include "mir/graphics/display_configuration_policy.h"
28#include "mir/graphics/overlapping_output_grouping.h"
29#include "mir/graphics/gl_context.h"
30#include "mir/graphics/gl_config.h"
31#include "mir/graphics/virtual_output.h"
32#include "mir/graphics/egl_error.h"
33#include "mir/graphics/display_buffer.h"
34#include "mir/renderer/gl/render_target.h"
35
36#include <drm/drm.h>
37#include <xf86drmMode.h>
38#include <sys/ioctl.h>
39#include <system_error>
40#include <boost/throw_exception.hpp>
41
42namespace mg = mir::graphics;
43namespace mge = mir::graphics::eglstream;
44namespace mgk = mir::graphics::kms;
45
46namespace
47{
48EGLConfig choose_config(EGLDisplay display, mg::GLConfig const& requested_config)
49{
50 EGLint const config_attr[] = {
51 EGL_SURFACE_TYPE, EGL_STREAM_BIT_KHR,
52 EGL_RED_SIZE, 8,
53 EGL_GREEN_SIZE, 8,
54 EGL_BLUE_SIZE, 8,
55 EGL_ALPHA_SIZE, 0,
56 EGL_DEPTH_SIZE, requested_config.depth_buffer_bits(),
57 EGL_STENCIL_SIZE, requested_config.stencil_buffer_bits(),
58 EGL_RENDERABLE_TYPE, MIR_SERVER_EGL_OPENGL_BIT,
59 EGL_NONE
60 };
61
62 EGLint num_egl_configs;
63 EGLConfig egl_config;
64 if (eglChooseConfig(display, config_attr, &egl_config, 1, &num_egl_configs) != EGL_TRUE)
65 {
66 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to chose EGL config"));
67 }
68 else if (num_egl_configs != 1)
69 {
70 BOOST_THROW_EXCEPTION(std::runtime_error{"Failed to find compatible EGL config"});
71 }
72
73 return egl_config;
74}
75
76EGLContext create_context(EGLDisplay display, EGLConfig config)
77{
78 eglBindAPI(MIR_SERVER_EGL_OPENGL_API);
79
80 EGLint const context_attr[] = {
81#if MIR_SERVER_EGL_OPENGL_BIT == EGL_OPENGL_ES2_BIT
82 EGL_CONTEXT_CLIENT_VERSION, 2,
83#endif
84 EGL_NONE
85 };
86
87 EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attr);
88 if (context == EGL_NO_CONTEXT)
89 {
90 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL context"));
91 }
92
93 return context;
94}
95
96EGLContext create_context(EGLDisplay display, EGLConfig config, EGLContext shared_context)
97{
98 eglBindAPI(MIR_SERVER_EGL_OPENGL_API);
99
100 EGLint const context_attr[] = {
101#if MIR_SERVER_EGL_OPENGL_BIT == EGL_OPENGL_ES2_BIT
102 EGL_CONTEXT_CLIENT_VERSION, 2,
103#endif
104 EGL_NONE
105 };
106
107 EGLContext context = eglCreateContext(display, config, shared_context, context_attr);
108 if (context == EGL_NO_CONTEXT)
109 {
110 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL context"));
111 }
112
113 return context;
114}
115
116class DisplayBuffer
117 : public mg::DisplaySyncGroup,
118 public mg::DisplayBuffer,
119 public mg::NativeDisplayBuffer,
120 public mir::renderer::gl::RenderTarget
121{
122public:
123 DisplayBuffer(EGLDisplay dpy, EGLContext ctx, EGLConfig config, mge::kms::EGLOutput const& output)
124 : dpy{dpy},
125 ctx{create_context(dpy, config, ctx)},
126 layer{output.output_layer()},
127 view_area_{output.top_left, output.size()}
128 {
129 EGLint const stream_attribs[] = {
130 EGL_STREAM_FIFO_LENGTH_KHR, 1,
131 EGL_NONE
132 };
133 output_stream = eglCreateStreamKHR(dpy, stream_attribs);
134 if (output_stream == EGL_NO_STREAM_KHR)
135 {
136 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGLStream"));
137 }
138
139 EGLAttrib swap_interval;
140 if (eglQueryOutputLayerAttribEXT(dpy, layer, EGL_SWAP_INTERVAL_EXT, &swap_interval) != EGL_TRUE)
141 {
142 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to query swap interval"));
143 }
144
145 if (eglOutputLayerAttribEXT(dpy, layer, EGL_SWAP_INTERVAL_EXT, 1) != EGL_TRUE)
146 {
147 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to set swap interval"));
148 }
149
150 if (eglStreamConsumerOutputEXT(dpy, output_stream, output.output_layer()) == EGL_FALSE)
151 {
152 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to attach EGLStream to output"));
153 };
154
155 EGLint const surface_attribs[] = {
156 EGL_WIDTH, output.size().width.as_int(),
157 EGL_HEIGHT, output.size().height.as_int(),
158 EGL_NONE,
159 };
160 surface = eglCreateStreamProducerSurfaceKHR(dpy, config, output_stream, surface_attribs);
161 if (surface == EGL_NO_SURFACE)
162 {
163 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create StreamProducerSurface"));
164 }
165
166 }
167
168 /* gl::RenderTarget */
169 void make_current() override
170 {
171 if (eglMakeCurrent(dpy, surface, surface, ctx) != EGL_TRUE)
172 {
173 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to make context current"));
174 }
175 }
176
177 void release_current() override
178 {
179 if (eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) != EGL_TRUE)
180 {
181 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to release context"));
182 }
183 }
184
185 void swap_buffers() override
186 {
187 if (eglSwapBuffers(dpy, surface) != EGL_TRUE)
188 {
189 BOOST_THROW_EXCEPTION(mg::egl_error("eglSwapBuffers failed"));
190 }
191 }
192
193 mir::geometry::Rectangle view_area() const override
194 {
195 return view_area_;
196 }
197
198 bool post_renderables_if_optimizable(const mir::graphics::RenderableList& /*renderlist*/) override
199 {
200 return false;
201 }
202
203 MirOrientation orientation() const override
204 {
205 return mir_orientation_normal;
206 }
207
208 MirMirrorMode mirror_mode() const override
209 {
210 return mir_mirror_mode_none;
211 }
212
213 mir::graphics::NativeDisplayBuffer* native_display_buffer() override
214 {
215 return this;
216 }
217
218 void for_each_display_buffer(const std::function<void(mir::graphics::DisplayBuffer&)>& f) override
219 {
220 f(*this);
221 }
222
223 void post() override
224 {
225
226 }
227
228 void bind() override
229 {
230 }
231
232 std::chrono::milliseconds recommended_sleep() const override
233 {
234 return std::chrono::milliseconds{0};
235 }
236
237private:
238 EGLDisplay dpy;
239 EGLContext ctx;
240 EGLOutputLayerEXT layer;
241 mir::geometry::Rectangle const view_area_;
242 EGLStreamKHR output_stream;
243 EGLSurface surface;
244};
245}
246
247mge::Display::Display(
248 mir::Fd drm_node,
249 EGLDisplay display,
250 std::shared_ptr<DisplayConfigurationPolicy> const& configuration_policy,
251 GLConfig const& gl_conf)
252 : drm_node{drm_node},
253 display{display},
254 config{choose_config(display, gl_conf)},
255 context{create_context(display, config)},
256 display_configuration{this->drm_node, display}
257{
258 auto ret = drmSetClientCap(drm_node, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
259 if (ret != 0)
260 {
261 BOOST_THROW_EXCEPTION(std::system_error(-ret, std::system_category(), "Request for Universal Planes support failed"));
262 }
263
264 ret = drmSetClientCap(drm_node, DRM_CLIENT_CAP_ATOMIC, 1);
265 if (ret != 0)
266 {
267 BOOST_THROW_EXCEPTION(std::system_error(-ret, std::system_category(), "Request for Atomic Modesetting support failed"));
268 }
269
270 configuration_policy->apply_to(display_configuration);
271
272 configure(display_configuration);
273}
274
275void mge::Display::for_each_display_sync_group(const std::function<void(DisplaySyncGroup&)>& f)
276{
277 for (auto& group : active_sync_groups)
278 {
279 f(*group);
280 }
281}
282
283std::unique_ptr<mg::DisplayConfiguration> mge::Display::configuration() const
284{
285 return display_configuration.clone();
286}
287
288void mge::Display::configure(DisplayConfiguration const& conf)
289{
290 auto kms_conf = dynamic_cast<KMSDisplayConfiguration const&>(conf);
291 active_sync_groups.clear();
292 kms_conf.for_each_output([this, &conf](kms::EGLOutput const& output)
293 {
294 if (output.used)
295 {
296 const_cast<kms::EGLOutput&>(output).configure(output.current_mode_index);
297 active_sync_groups.emplace_back(std::make_unique<::DisplayBuffer>(display, context, config, output));
298 }
299 });
300}
301
302void mge::Display::register_configuration_change_handler(
303 EventHandlerRegister& /*handlers*/,
304 DisplayConfigurationChangeHandler const& /*conf_change_handler*/)
305{
306}
307
308void mge::Display::register_pause_resume_handlers(
309 EventHandlerRegister& /*handlers*/,
310 DisplayPauseHandler const& /*pause_handler*/,
311 DisplayResumeHandler const& /*resume_handler*/)
312{
313}
314
315void mge::Display::pause()
316{
317
318}
319
320void mge::Display::resume()
321{
322
323}
324
325std::shared_ptr<mg::Cursor> mge::Display::create_hardware_cursor(
326 std::shared_ptr<CursorImage> const& /*initial_image*/)
327{
328 // TODO: Find the cursor plane, and use it.
329 return nullptr;
330}
331
332std::unique_ptr<mg::GLContext> mge::Display::create_gl_context()
333{
334 class GLContext : public mg::GLContext
335 {
336 public:
337 GLContext(EGLDisplay display, EGLContext context)
338 : display{display},
339 context{context}
340 {
341 }
342
343 void make_current() const override
344 {
345 eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context);
346 }
347
348 void release_current() const override
349 {
350 eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
351 }
352
353 private:
354 EGLDisplay display;
355 EGLContext context;
356 };
357 return std::make_unique<GLContext>(display, context);
358}
359
360std::unique_ptr<mg::VirtualOutput> mge::Display::create_virtual_output(int /*width*/, int /*height*/)
361{
362 return nullptr;
363}
0364
=== added file 'src/platforms/eglstream-kms/server/display.h'
--- src/platforms/eglstream-kms/server/display.h 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/server/display.h 2016-06-08 13:28:19 +0000
@@ -0,0 +1,82 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#ifndef MIR_PLATFORMS_EGLSTREAM_KMS_DISPLAY_H_
20#define MIR_PLATFORMS_EGLSTREAM_KMS_DISPLAY_H_
21
22#include "mir/graphics/display.h"
23#include "kms_display_configuration.h"
24#include "mir/fd.h"
25
26namespace mir
27{
28namespace graphics
29{
30class DisplayConfigurationPolicy;
31class GLConfig;
32
33namespace eglstream
34{
35
36class Display : public mir::graphics::Display
37{
38public:
39 Display(
40 mir::Fd drm_node,
41 EGLDisplay display,
42 std::shared_ptr<DisplayConfigurationPolicy> const& configuration_policy,
43 GLConfig const& gl_conf);
44
45 void for_each_display_sync_group(const std::function<void(DisplaySyncGroup&)>& f) override;
46
47 std::unique_ptr<DisplayConfiguration> configuration() const override;
48
49 void configure(DisplayConfiguration const& conf) override;
50
51 void register_configuration_change_handler(EventHandlerRegister& handlers,
52 DisplayConfigurationChangeHandler const& conf_change_handler) override;
53
54 void register_pause_resume_handlers(EventHandlerRegister& handlers,
55 DisplayPauseHandler const& pause_handler, DisplayResumeHandler const& resume_handler) override;
56
57 void pause() override;
58
59 void resume() override;
60
61 std::shared_ptr<Cursor> create_hardware_cursor(std::shared_ptr<CursorImage> const& initial_image) override;
62
63 std::unique_ptr<GLContext> create_gl_context() override;
64
65 std::unique_ptr<VirtualOutput> create_virtual_output(int width, int height) override;
66
67private:
68 mir::Fd const drm_node;
69 EGLDisplay display;
70 EGLConfig config;
71 EGLContext context;
72 KMSDisplayConfiguration display_configuration;
73 std::vector<std::unique_ptr<DisplaySyncGroup>> active_sync_groups;
74 std::shared_ptr<DisplayConfigurationPolicy> const configuration_policy;
75};
76
77}
78}
79
80}
81
82#endif // MIR_PLATFORMS_EGLSTREAM_KMS_DISPLAY_H_
083
=== added file 'src/platforms/eglstream-kms/server/egl_output.cpp'
--- src/platforms/eglstream-kms/server/egl_output.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/server/egl_output.cpp 2016-06-08 13:28:19 +0000
@@ -0,0 +1,359 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#include <epoxy/egl.h>
20
21#include "egl_output.h"
22#include "mir/graphics/egl_error.h"
23#include "kms-utils/kms_connector.h"
24
25#include <cstring>
26#include <drm/drm.h>
27#include <sys/ioctl.h>
28#include <vector>
29#include <boost/throw_exception.hpp>
30#include <unordered_map>
31#include <tuple>
32#include <sys/mman.h>
33
34namespace mg = mir::graphics;
35namespace mge = mg::eglstream;
36namespace mgek = mge::kms;
37namespace mgk = mg::kms;
38namespace geom = mir::geometry;
39
40namespace
41{
42namespace
43{
44class DumbFb
45{
46public:
47 DumbFb(int drm_fd, uint32_t width, uint32_t height)
48 : drm_fd{drm_fd}
49 {
50 struct drm_mode_create_dumb params = {};
51
52 params.bpp = 32;
53 params.height = height;
54 params.width = width;
55
56 if (ioctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &params) != 0)
57 {
58 BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Failed to create dumb buffer"}));
59 }
60
61 gem_handle = params.handle;
62 pitch_ = params.pitch;
63
64 auto ret = drmModeAddFB(drm_fd, width, height, 24, 32, params.pitch, params.handle, &fb_id);
65 if (ret)
66 {
67 BOOST_THROW_EXCEPTION((std::system_error{-ret, std::system_category(), "Failed to attach dumb buffer to FB"}));
68 }
69
70 struct drm_mode_map_dumb map_request = {};
71
72 map_request.handle = gem_handle;
73
74 ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_request);
75 if (ret)
76 {
77 BOOST_THROW_EXCEPTION((std::system_error{-ret, std::system_category(), "Failed to map dumb buffer"}));
78 }
79
80 auto map = mmap(0, params.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd, map_request.offset);
81 if (map == MAP_FAILED)
82 {
83 BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Failed to mmap() buffer"}));
84 }
85 }
86 ~DumbFb() noexcept(false)
87 {
88 struct drm_mode_destroy_dumb params = { gem_handle };
89
90 if (ioctl(drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &params) != 0)
91 {
92 if (!std::uncaught_exception())
93 {
94 BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Failed to destroy dumb buffer"}));
95 }
96 }
97 }
98
99 uint32_t handle() const
100 {
101 return gem_handle;
102 }
103
104 uint32_t pitch() const
105 {
106 return pitch_;
107 }
108
109 uint32_t id() const
110 {
111 return fb_id;
112 }
113
114private:
115 int const drm_fd;
116 uint32_t fb_id;
117 uint32_t gem_handle;
118 uint32_t pitch_;
119};
120
121}
122
123uint32_t kms_id_from_port(EGLDisplay dpy, EGLOutputPortEXT port)
124{
125 EGLAttrib kms_connector_id;
126 if (eglQueryOutputPortAttribEXT(dpy, port, EGL_DRM_CONNECTOR_EXT, &kms_connector_id) != EGL_TRUE)
127 {
128 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to get EGLOutputPort → KMS connector ID mapping"));
129 }
130 return static_cast<uint32_t>(kms_connector_id);
131}
132
133void refresh_connector(int drm_fd, mgk::DRMModeConnectorUPtr& connector)
134{
135 connector = mgk::get_connector(drm_fd, connector->connector_id);
136}
137}
138
139mgek::EGLOutput::EGLOutput(
140 int drm_fd,
141 EGLDisplay dpy,
142 EGLOutputPortEXT connector)
143 : drm_fd{drm_fd},
144 display{dpy},
145 port{connector},
146 connector{mgk::get_connector(drm_fd, kms_id_from_port(dpy, port))}
147{
148
149}
150
151mgek::EGLOutput::~EGLOutput() noexcept(false)
152{
153 auto const uncaught_exception = std::uncaught_exception();
154 try
155 {
156 restore_saved_crtc();
157 }
158 catch(...)
159 {
160 if (!uncaught_exception)
161 {
162 throw;
163 }
164 }
165}
166
167void mgek::EGLOutput::reset()
168{
169 /* Update the connector to ensure we have the latest information */
170 refresh_connector(drm_fd, connector);
171
172 // TODO: What if we can't locate the DPMS property?
173 // TODO: Replace with mgk::ObjectProperties
174 for (int i = 0; i < connector->count_props; i++)
175 {
176 auto prop = drmModeGetProperty(drm_fd, connector->props[i]);
177 if (prop && (prop->flags & DRM_MODE_PROP_ENUM)) {
178 if (!strcmp(prop->name, "DPMS"))
179 {
180 dpms_enum_id = connector->props[i];
181 drmModeFreeProperty(prop);
182 break;
183 }
184 drmModeFreeProperty(prop);
185 }
186 }
187}
188
189geom::Size mgek::EGLOutput::size() const
190{
191 drmModeModeInfo const& mode = connector->modes[mode_index];
192 return {mode.hdisplay, mode.vdisplay};
193}
194
195int mgek::EGLOutput::max_refresh_rate() const
196{
197 // TODO: In future when DRM exposes FreeSync/Adaptive Sync/G-Sync info
198 // this value may be calculated differently.
199 drmModeModeInfo const& current_mode = connector->modes[mode_index];
200 return current_mode.vrefresh;
201}
202
203void mgek::EGLOutput::configure(size_t kms_mode_index)
204{
205 mode_index = kms_mode_index;
206 auto const width = connector->modes[kms_mode_index].hdisplay;
207 auto const height = connector->modes[kms_mode_index].vdisplay;
208
209 std::unique_ptr<drmModeAtomicReq, void(*)(drmModeAtomicReqPtr)>
210 request{drmModeAtomicAlloc(), &drmModeAtomicFree};
211
212 mgk::DRMModeCrtcUPtr crtc;
213 mgk::DRMModePlaneUPtr plane;
214
215 std::tie(crtc, plane) = mgk::find_crtc_with_primary_plane(drm_fd, connector);
216 auto const crtc_id = crtc->crtc_id;
217
218 uint32_t mode_id{0};
219 auto ret = drmModeCreatePropertyBlob(
220 drm_fd,
221 &connector->modes[kms_mode_index],
222 sizeof(connector->modes[kms_mode_index]),
223 &mode_id);
224
225 if (ret != 0)
226 {
227 BOOST_THROW_EXCEPTION(
228 std::system_error(-ret, std::system_category(), "Failed to create DRM Mode property blob"));
229 }
230
231 DumbFb dummy{drm_fd, width, height};
232
233 mgk::ObjectProperties crtc_props{drm_fd, crtc_id, DRM_MODE_OBJECT_CRTC};
234
235 /* Activate the CRTC and set the mode */
236 drmModeAtomicAddProperty(request.get(), crtc_id, crtc_props.id_for("MODE_ID"), mode_id);
237 drmModeAtomicAddProperty(request.get(), crtc_id, crtc_props.id_for("ACTIVE"), 1);
238
239 /* Set CRTC for the output */
240 auto const connector_id = connector->connector_id;
241 mgk::ObjectProperties connector_props{drm_fd, connector_id, DRM_MODE_OBJECT_CONNECTOR};
242 drmModeAtomicAddProperty(request.get(), connector_id, connector_props.id_for("CRTC_ID"), crtc_id);
243
244 /* Set up the output plane... */
245 auto const plane_id = plane->plane_id;
246 mgk::ObjectProperties plane_props{drm_fd, plane_id, DRM_MODE_OBJECT_PLANE};
247
248 /* Source viewport. Coordinates are 16.16 fixed point format */
249 drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("SRC_X"), 0);
250 drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("SRC_Y"), 0);
251 drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("SRC_W"), width << 16);
252 drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("SRC_H"), height << 16);
253
254 /* Destination viewport. Coordinates are *not* 16.16 */
255 drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("CRTC_X"), 0);
256 drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("CRTC_Y"), 0);
257 drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("CRTC_W"), width);
258 drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("CRTC_H"), height);
259
260 /* Set a surface for the plane, and connect to the CRTC */
261 drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("FB_ID"), dummy.id());
262 drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("CRTC_ID"), crtc_id);
263
264 /* We don't monitor the DRM events (yet), so have no userdata */
265 ret = drmModeAtomicCommit(drm_fd, request.get(), DRM_MODE_ATOMIC_ALLOW_MODESET, nullptr);
266
267 if (ret != 0)
268 {
269 BOOST_THROW_EXCEPTION(
270 std::system_error(-ret, std::system_category(), "Failed to commit atomic KMS configuration change"));
271 }
272
273 EGLAttrib const crtc_filter[] = {
274 EGL_DRM_PLANE_EXT, plane_id,
275 EGL_NONE};
276 int found_layers{0};
277 if (eglGetOutputLayersEXT(display, crtc_filter, &layer, 1, &found_layers) != EGL_TRUE)
278 {
279 BOOST_THROW_EXCEPTION((mg::egl_error("Failed to find EGLOutputEXT corresponding to DRM CRTC")));
280 }
281 if (found_layers != 1)
282 {
283 BOOST_THROW_EXCEPTION(std::runtime_error{"Failed to find EGLOutputEXT corresponding to DRM CRTC"});
284 }
285
286 using_saved_crtc = false;
287}
288
289EGLOutputLayerEXT mgek::EGLOutput::output_layer() const
290{
291 return layer;
292}
293
294void mgek::EGLOutput::clear_crtc()
295{
296 using namespace std::string_literals;
297 mgk::DRMModeCrtcUPtr crtc;
298 try
299 {
300 crtc = mgk::find_crtc_for_connector(drm_fd, connector);
301 }
302 catch (std::runtime_error const&)
303 {
304 /*
305 * In order to actually clear the output, we need to have a crtc
306 * connected to the output/connector so that we can disconnect
307 * it. However, not being able to get a crtc is OK, since it means
308 * that the output cannot be displaying anything anyway.
309 */
310 return;
311 }
312 auto const crtc_id = crtc->crtc_id;
313
314 auto result = drmModeSetCrtc(drm_fd, crtc_id,
315 0, 0, 0, nullptr, 0, nullptr);
316 if (result)
317 {
318 BOOST_THROW_EXCEPTION((
319 std::system_error{
320 -result,
321 std::system_category(),
322 "Couldn't clear output "s + mgk::connector_name(connector)}));
323 }
324}
325
326void mgek::EGLOutput::restore_saved_crtc()
327{
328 if (!using_saved_crtc)
329 {
330 auto result = drmModeSetCrtc(
331 drm_fd,
332 saved_crtc.crtc_id,
333 saved_crtc.buffer_id,
334 saved_crtc.x, saved_crtc.y,
335 &connector->connector_id,
336 1,
337 &saved_crtc.mode);
338
339 if (result != 0)
340 {
341 BOOST_THROW_EXCEPTION((std::system_error{-result, std::system_category(), "Failed to set CRTC"}));
342 }
343
344 using_saved_crtc = true;
345 }
346}
347
348void mgek::EGLOutput::set_power_mode(MirPowerMode mode)
349{
350 auto ret = drmModeConnectorSetProperty(
351 drm_fd,
352 connector->connector_id,
353 dpms_enum_id,
354 mode);
355 if (ret)
356 {
357 BOOST_THROW_EXCEPTION((std::system_error{-ret, std::system_category(), "Failed to set output power mode"}));
358 }
359}
0360
=== added file 'src/platforms/eglstream-kms/server/egl_output.h'
--- src/platforms/eglstream-kms/server/egl_output.h 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/server/egl_output.h 2016-06-08 13:28:19 +0000
@@ -0,0 +1,79 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#ifndef MIR_GRAPHICS_EGLSTREAM_KMS_OUTPUT_H_
20#define MIR_GRAPHICS_EGLSTREAM_KMS_OUTPUT_H_
21
22#include "kms-utils/drm_mode_resources.h"
23#include "mir/geometry/size.h"
24#include "mir/geometry/point.h"
25#include "mir/geometry/displacement.h"
26#include "mir/graphics/display_configuration.h"
27#include "mir_toolkit/common.h"
28
29#include <epoxy/egl.h>
30
31namespace mir
32{
33namespace graphics
34{
35namespace eglstream
36{
37
38namespace kms
39{
40class EGLOutput : public DisplayConfigurationOutput
41{
42public:
43 EGLOutput(int drm_fd, EGLDisplay dpy, EGLOutputPortEXT connector);
44 ~EGLOutput() noexcept(false);
45
46 void reset();
47 void configure(size_t kms_mode_index);
48 geometry::Size size() const;
49 int max_refresh_rate() const;
50
51 EGLOutputLayerEXT output_layer() const;
52 void clear_crtc();
53
54 void set_power_mode(MirPowerMode mode);
55
56private:
57 void restore_saved_crtc();
58
59 int const drm_fd;
60
61 EGLDisplay display;
62 EGLOutputPortEXT port;
63 EGLOutputLayerEXT layer;
64
65 graphics::kms::DRMModeConnectorUPtr connector;
66
67 size_t mode_index;
68 drmModeCrtc saved_crtc;
69 bool using_saved_crtc;
70
71 int dpms_enum_id;
72};
73
74}
75}
76}
77}
78
79#endif /* MIR_GRAPHICS_EGLSTREAM_KMS_KMS_OUTPUT_H_ */
080
=== added file 'src/platforms/eglstream-kms/server/kms_display_configuration.cpp'
--- src/platforms/eglstream-kms/server/kms_display_configuration.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/server/kms_display_configuration.cpp 2016-06-08 13:28:19 +0000
@@ -0,0 +1,331 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#include <epoxy/egl.h>
20
21#include "kms_display_configuration.h"
22#include "kms-utils/drm_mode_resources.h"
23#include "mir/graphics/pixel_format_utils.h"
24#include "mir/graphics/egl_error.h"
25
26#include <cmath>
27#include <limits>
28
29#include <boost/throw_exception.hpp>
30#include <stdexcept>
31#include <algorithm>
32
33namespace mg = mir::graphics;
34namespace mge = mir::graphics::eglstream;
35namespace mgk = mir::graphics::kms;
36
37namespace geom = mir::geometry;
38
39namespace
40{
41
42bool kms_modes_are_equal(drmModeModeInfo const& info1, drmModeModeInfo const& info2)
43{
44 return (info1.clock == info2.clock &&
45 info1.hdisplay == info2.hdisplay &&
46 info1.hsync_start == info2.hsync_start &&
47 info1.hsync_end == info2.hsync_end &&
48 info1.htotal == info2.htotal &&
49 info1.hskew == info2.hskew &&
50 info1.vdisplay == info2.vdisplay &&
51 info1.vsync_start == info2.vsync_start &&
52 info1.vsync_end == info2.vsync_end &&
53 info1.vtotal == info2.vtotal);
54}
55
56double calculate_vrefresh_hz(drmModeModeInfo const& mode)
57{
58 if (mode.htotal == 0 || mode.vtotal == 0)
59 return 0.0;
60
61 /* mode.clock is in KHz */
62 double hz = (mode.clock * 100000LL /
63 ((long)mode.htotal * (long)mode.vtotal)
64 ) / 100.0;
65
66 // Actually we don't need floating point at all for this...
67 // TODO: Consider converting our structs to fixed-point ints
68 return hz;
69}
70
71mg::DisplayConfigurationOutputType
72kms_connector_type_to_output_type(uint32_t connector_type)
73{
74 return static_cast<mg::DisplayConfigurationOutputType>(connector_type);
75}
76
77std::vector<std::shared_ptr<mge::kms::EGLOutput>> create_outputs(int drm_fd, EGLDisplay display)
78{
79 mgk::DRMModeResources resources{drm_fd};
80
81 std::vector<std::shared_ptr<mge::kms::EGLOutput>> outputs;
82
83 for (auto const& connector : resources.connectors())
84 {
85 EGLOutputPortEXT port;
86 int num_ports;
87 EGLAttrib const select_connector[] = {
88 EGL_DRM_CONNECTOR_EXT, connector->connector_id,
89 EGL_NONE
90 };
91 if (eglGetOutputPortsEXT(display, select_connector, &port, 1, &num_ports) != EGL_TRUE)
92 {
93 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to find EGLOutputPort corresponding to DRM connector"));
94 }
95 if (num_ports != 1)
96 {
97 BOOST_THROW_EXCEPTION(std::runtime_error("Failed to find EGLOutputPort corresponding to DRM connector"));
98 }
99 outputs.push_back(std::make_shared<mge::kms::EGLOutput>(drm_fd, display, port));
100 auto& output = outputs.back();
101
102 // TODO: This should all be owned by mgek::EGLOutput
103
104 output->id = mg::DisplayConfigurationOutputId{static_cast<int>(connector->connector_id)};
105 output->card_id = mg::DisplayConfigurationCardId{0};
106 output->type = kms_connector_type_to_output_type(connector->connector_type);
107 output->physical_size_mm = geom::Size{connector->mmWidth, connector->mmHeight};
108 output->connected = connector->connection == DRM_MODE_CONNECTED;
109 output->pixel_formats = {
110 mir_pixel_format_argb_8888,
111 mir_pixel_format_xrgb_8888
112 };
113
114 uint32_t const invalid_mode_index = std::numeric_limits<uint32_t>::max();
115 output->current_mode_index = invalid_mode_index;
116 output->preferred_mode_index = invalid_mode_index;
117
118 /* Get information about the current mode */
119 mgk::DRMModeCrtcUPtr current_crtc;
120 if (connector->encoder_id)
121 {
122 auto encoder = mgk::get_encoder(drm_fd, connector->encoder_id);
123 if (encoder->crtc_id)
124 {
125 current_crtc = mgk::get_crtc(drm_fd, encoder->crtc_id);
126 }
127 }
128
129 /* Add all the available modes and find the current and preferred one */
130 for (int m = 0; m < connector->count_modes; m++)
131 {
132 drmModeModeInfo &mode_info = connector->modes[m];
133
134 geom::Size size{mode_info.hdisplay, mode_info.vdisplay};
135
136 double vrefresh_hz = calculate_vrefresh_hz(mode_info);
137
138 output->modes.push_back({size, vrefresh_hz});
139
140 if (current_crtc && kms_modes_are_equal(mode_info, current_crtc->mode))
141 output->current_mode_index = m;
142
143 if ((mode_info.type & DRM_MODE_TYPE_PREFERRED) == DRM_MODE_TYPE_PREFERRED)
144 output->preferred_mode_index = m;
145 }
146
147
148 output->current_format = mir_pixel_format_xrgb_8888;
149 output->power_mode = mir_power_mode_on;
150 output->orientation = mir_orientation_normal;
151 output->scale = 1.0f;
152 output->form_factor = mir_form_factor_monitor;
153 output->used = false;
154 }
155
156 return outputs;
157}
158
159mg::DisplayConfigurationCard create_card(int drm_fd)
160{
161 mgk::DRMModeResources resources{drm_fd};
162
163 size_t max_outputs = std::min(resources.num_crtcs(), resources.num_connectors());
164 return {mg::DisplayConfigurationCardId{0}, max_outputs};
165}
166
167}
168
169mge::KMSDisplayConfiguration::KMSDisplayConfiguration(int drm_fd, EGLDisplay dpy)
170 : drm_fd{drm_fd},
171 card{create_card(drm_fd)},
172 outputs{create_outputs(drm_fd, dpy)}
173{
174 update();
175}
176
177mge::KMSDisplayConfiguration::KMSDisplayConfiguration(
178 KMSDisplayConfiguration const& conf)
179 : mg::DisplayConfiguration(),
180 drm_fd{conf.drm_fd},
181 card(conf.card),
182 outputs{conf.outputs}
183{
184}
185
186void mge::KMSDisplayConfiguration::for_each_card(
187 std::function<void(DisplayConfigurationCard const&)> f) const
188{
189 f(card);
190}
191
192void mge::KMSDisplayConfiguration::for_each_output(
193 std::function<void(DisplayConfigurationOutput const&)> f) const
194{
195 for (auto const& output : outputs)
196 f(*output);
197}
198
199void mge::KMSDisplayConfiguration::for_each_output(
200 std::function<void(UserDisplayConfigurationOutput&)> f)
201{
202 for (auto& output : outputs)
203 {
204 UserDisplayConfigurationOutput user(*output);
205 f(user);
206 }
207}
208
209std::unique_ptr<mg::DisplayConfiguration> mge::KMSDisplayConfiguration::clone() const
210{
211 return std::make_unique<KMSDisplayConfiguration>(*this);
212}
213
214uint32_t mge::KMSDisplayConfiguration::get_kms_connector_id(
215 DisplayConfigurationOutputId id) const
216{
217 auto iter = find_output_with_id(id);
218
219 if (iter == outputs.end())
220 {
221 BOOST_THROW_EXCEPTION(
222 std::out_of_range("Failed to find DisplayConfigurationOutput with provided id"));
223 }
224
225 return id.as_value();
226}
227
228size_t mge::KMSDisplayConfiguration::get_kms_mode_index(
229 DisplayConfigurationOutputId id,
230 size_t conf_mode_index) const
231{
232 auto iter = find_output_with_id(id);
233
234 if (iter == outputs.end() || conf_mode_index >= (*iter)->modes.size())
235 {
236 BOOST_THROW_EXCEPTION(
237 std::out_of_range("Failed to find valid mode index for DisplayConfigurationOutput with provided id/mode_index"));
238 }
239
240 return conf_mode_index;
241}
242void mge::KMSDisplayConfiguration::update()
243{
244 mgk::DRMModeResources resources{drm_fd};
245
246 for (auto const& connector : resources.connectors())
247 {
248 update_output(resources, connector, **find_output_with_id(DisplayConfigurationOutputId(connector->connector_id)));
249 };
250}
251
252void mge::KMSDisplayConfiguration::for_each_output(
253 std::function<void(kms::EGLOutput const&)> const& f) const
254{
255 for (auto const& output : outputs)
256 {
257 f(*output);
258 }
259}
260
261void mge::KMSDisplayConfiguration::update_output(
262 mgk::DRMModeResources const& resources,
263 mgk::DRMModeConnectorUPtr const& connector,
264 kms::EGLOutput& output)
265{
266 output.physical_size_mm = geom::Size{connector->mmWidth, connector->mmHeight};
267 output.connected = connector->connection == DRM_MODE_CONNECTED;
268
269 uint32_t const invalid_mode_index = std::numeric_limits<uint32_t>::max();
270
271 output.modes.clear();
272 output.current_mode_index = invalid_mode_index;
273
274 drmModeModeInfo* current_mode_info{nullptr};
275 mgk::DRMModeCrtcUPtr current_crtc;
276 if (connector->encoder_id)
277 {
278 auto encoder = resources.encoder(connector->encoder_id);
279 if (encoder->crtc_id)
280 {
281 current_crtc = resources.crtc(encoder->crtc_id);
282 current_mode_info = &current_crtc->mode;
283 }
284 }
285
286 /* Add all the available modes and find the current and preferred one */
287 for (int m = 0; m < connector->count_modes; m++)
288 {
289 drmModeModeInfo& mode_info = connector->modes[m];
290
291 geom::Size size{mode_info.hdisplay, mode_info.vdisplay};
292
293 double vrefresh_hz = calculate_vrefresh_hz(mode_info);
294
295 output.modes.push_back({size, vrefresh_hz});
296
297 if (current_mode_info && kms_modes_are_equal(mode_info, *current_mode_info))
298 output.current_mode_index = m;
299
300 if ((mode_info.type & DRM_MODE_TYPE_PREFERRED) == DRM_MODE_TYPE_PREFERRED)
301 output.preferred_mode_index = m;
302 }
303
304 if (output.modes.empty())
305 {
306 output.preferred_mode_index = invalid_mode_index;
307 }
308 output.physical_size_mm = geom::Size{connector->mmWidth, connector->mmHeight};
309}
310
311std::vector<std::shared_ptr<mge::kms::EGLOutput>>::iterator
312mge::KMSDisplayConfiguration::find_output_with_id(mg::DisplayConfigurationOutputId id)
313{
314 return std::find_if(
315 outputs.begin(), outputs.end(),
316 [id](std::shared_ptr<DisplayConfigurationOutput> const& output)
317 {
318 return output->id == id;
319 });
320}
321
322std::vector<std::shared_ptr<mge::kms::EGLOutput>>::const_iterator
323mge::KMSDisplayConfiguration::find_output_with_id(mg::DisplayConfigurationOutputId id) const
324{
325 return std::find_if(
326 outputs.begin(), outputs.end(),
327 [id](std::shared_ptr<DisplayConfigurationOutput> const& output)
328 {
329 return output->id == id;
330 });
331}
0332
=== added file 'src/platforms/eglstream-kms/server/kms_display_configuration.h'
--- src/platforms/eglstream-kms/server/kms_display_configuration.h 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/server/kms_display_configuration.h 2016-06-08 13:28:19 +0000
@@ -0,0 +1,70 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#ifndef MIR_PLATFORMS_EGLSTREAM_KMS_KMS_DISPLAY_CONFIGURATION_H_
20#define MIR_PLATFORMS_EGLSTREAM_KMS_KMS_DISPLAY_CONFIGURATION_H_
21
22#include "egl_output.h"
23
24#include "mir/graphics/display_configuration.h"
25
26
27#include <xf86drmMode.h>
28
29namespace mir
30{
31namespace graphics
32{
33namespace eglstream
34{
35
36class KMSDisplayConfiguration : public DisplayConfiguration
37{
38public:
39 KMSDisplayConfiguration(int drm_fd, EGLDisplay dpy);
40 KMSDisplayConfiguration(KMSDisplayConfiguration const& conf);
41
42 void for_each_card(std::function<void(DisplayConfigurationCard const&)> f) const override;
43 void for_each_output(std::function<void(DisplayConfigurationOutput const&)> f) const override;
44 void for_each_output(std::function<void(UserDisplayConfigurationOutput&)> f) override;
45 std::unique_ptr<DisplayConfiguration> clone() const override;
46
47 uint32_t get_kms_connector_id(DisplayConfigurationOutputId id) const;
48 size_t get_kms_mode_index(DisplayConfigurationOutputId id, size_t conf_mode_index) const;
49 void update();
50
51 void for_each_output(std::function<void(kms::EGLOutput const&)> const& f) const;
52
53private:
54 void update_output(
55 graphics::kms::DRMModeResources const& resources,
56 graphics::kms::DRMModeConnectorUPtr const& connector,
57 kms::EGLOutput& output);
58 std::vector<std::shared_ptr<kms::EGLOutput>>::iterator find_output_with_id(DisplayConfigurationOutputId id);
59 std::vector<std::shared_ptr<kms::EGLOutput>>::const_iterator find_output_with_id(DisplayConfigurationOutputId id) const;
60
61 int drm_fd;
62 DisplayConfigurationCard const card;
63 std::vector<std::shared_ptr<kms::EGLOutput>> outputs;
64};
65
66}
67}
68}
69
70#endif // MIR_PLATFORMS_EGLSTREAM_KMS_KMS_DISPLAY_CONFIGURATION_H_
071
=== added file 'src/platforms/eglstream-kms/server/platform.cpp'
--- src/platforms/eglstream-kms/server/platform.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/server/platform.cpp 2016-06-08 13:28:19 +0000
@@ -0,0 +1,162 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#include <epoxy/egl.h>
20
21#include "platform.h"
22#include "buffer_allocator.h"
23#include "display.h"
24#include "mir/graphics/platform_ipc_operations.h"
25#include "mir/graphics/platform_ipc_package.h"
26#include "mir/graphics/platform_operation_message.h"
27#include "mir/graphics/buffer_ipc_message.h"
28
29#include "mir/graphics/egl_error.h"
30
31#include <boost/throw_exception.hpp>
32#include <xf86drm.h>
33#include <fcntl.h>
34
35namespace mg = mir::graphics;
36namespace mge = mir::graphics::eglstream;
37
38namespace
39{
40// Our copy of eglext.h doesn't have this?
41int const EGL_DRM_MASTER_FD_EXT{0x333C};
42
43char const* drm_node_for_device(EGLDeviceEXT device)
44{
45 auto const device_path = eglQueryDeviceStringEXT(device, EGL_DRM_DEVICE_FILE_EXT);
46 if (!device_path)
47 {
48 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to determine DRM device node path from EGLDevice"));
49 }
50 return device_path;
51}
52}
53
54mge::Platform::Platform(
55 EGLDeviceEXT device,
56 std::shared_ptr<EmergencyCleanupRegistry> const& /*emergency_cleanup_registry*/,
57 std::shared_ptr<DisplayReport> const& /*report*/)
58 : device{device},
59 display{EGL_NO_DISPLAY},
60 drm_node{open(drm_node_for_device(device), O_RDWR | O_CLOEXEC)}
61{
62 using namespace std::literals;
63
64 if (drm_node == mir::Fd::invalid)
65 {
66 BOOST_THROW_EXCEPTION(std::system_error(
67 errno,
68 std::system_category(),
69 "Failed to open DRM device "s + drm_node_for_device(device)));
70 }
71
72 if (drmSetMaster(drm_node))
73 {
74 BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Failed to acquire DRM master"}));
75 }
76
77 int const drm_node_attrib[] = {
78 EGL_DRM_MASTER_FD_EXT, static_cast<int>(drm_node), EGL_NONE
79 };
80 display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, device, drm_node_attrib);
81
82 if (display == EGL_NO_DISPLAY)
83 {
84 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGLDisplay on the EGLDeviceEXT"));
85 }
86
87 EGLint major{1};
88 EGLint minor{4};
89 if (eglInitialize(display, &major, &minor) != EGL_TRUE)
90 {
91 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to initialise EGL"));
92 }
93 if (major != 1 || minor != 4)
94 {
95 BOOST_THROW_EXCEPTION((std::runtime_error{
96 "Incompatible EGL version"s +
97 "Wanted 1.4, got " + std::to_string(major) + "." + std::to_string(minor)}));
98 }
99}
100
101mir::UniqueModulePtr<mg::GraphicBufferAllocator> mge::Platform::create_buffer_allocator()
102{
103 return mir::make_module_ptr<mge::BufferAllocator>();
104}
105
106mir::UniqueModulePtr<mg::Display> mge::Platform::create_display(
107 std::shared_ptr<DisplayConfigurationPolicy> const& configuration_policy,
108 std::shared_ptr<GLConfig> const& gl_config)
109{
110 return mir::make_module_ptr<mge::Display>(drm_node, display, configuration_policy, *gl_config);
111}
112
113mir::UniqueModulePtr<mg::PlatformIpcOperations> mge::Platform::make_ipc_operations() const
114{
115 class NoIPCOperations : public mg::PlatformIpcOperations
116 {
117
118 public:
119 void pack_buffer(BufferIpcMessage& packer, Buffer const& buffer, BufferIpcMsgType msg_type) const override
120 {
121 if (msg_type == mg::BufferIpcMsgType::full_msg)
122 {
123 auto native_handle = buffer.native_buffer_handle();
124 for(auto i=0; i<native_handle->data_items; i++)
125 {
126 packer.pack_data(native_handle->data[i]);
127 }
128 for(auto i=0; i<native_handle->fd_items; i++)
129 {
130 packer.pack_fd(mir::Fd(IntOwnedFd{native_handle->fd[i]}));
131 }
132
133 packer.pack_stride(buffer.stride());
134 packer.pack_flags(native_handle->flags);
135 packer.pack_size(buffer.size());
136 }
137 }
138
139 void unpack_buffer(BufferIpcMessage& /*message*/, Buffer const& /*buffer*/) const override
140 {
141
142 }
143
144 std::shared_ptr<mg::PlatformIPCPackage> connection_ipc_package() override
145 {
146 return std::make_shared<mg::PlatformIPCPackage>(describe_graphics_module());
147 }
148
149 PlatformOperationMessage platform_operation(unsigned int const /*opcode*/,
150 PlatformOperationMessage const& /*message*/) override
151 {
152 BOOST_THROW_EXCEPTION(std::runtime_error{"No platform operations implemented"});
153 }
154 };
155
156 return mir::make_module_ptr<NoIPCOperations>();
157}
158
159EGLNativeDisplayType mge::Platform::egl_native_display() const
160{
161 return display;
162}
0163
=== added file 'src/platforms/eglstream-kms/server/platform.h'
--- src/platforms/eglstream-kms/server/platform.h 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/server/platform.h 2016-06-08 13:28:19 +0000
@@ -0,0 +1,66 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#ifndef MIR_PLATFORMS_EGLSTREAM_KMS_PLATFORM_H_
20#define MIR_PLATFORMS_EGLSTREAM_KMS_PLATFORM_H_
21
22#include "mir/graphics/platform.h"
23#include "mir/options/option.h"
24#include "mir/graphics/graphic_buffer_allocator.h"
25#include "mir/graphics/display.h"
26#include "mir/graphics/platform_ipc_operations.h"
27#include "mir/fd.h"
28
29#include <EGL/egl.h>
30#include <EGL/eglext.h>
31
32namespace mir
33{
34namespace graphics
35{
36namespace eglstream
37{
38class Platform : public mir::graphics::Platform
39{
40public:
41 Platform(
42 EGLDeviceEXT device,
43 std::shared_ptr<EmergencyCleanupRegistry> const& /*emergency_cleanup_registry*/,
44 std::shared_ptr<DisplayReport> const& /*report*/);
45 ~Platform() = default;
46
47 UniqueModulePtr<GraphicBufferAllocator> create_buffer_allocator() override;
48
49 UniqueModulePtr<Display> create_display(
50 std::shared_ptr<DisplayConfigurationPolicy> const& /*initial_conf_policy*/,
51 std::shared_ptr<GLConfig> const& /*gl_config*/) override;
52
53 UniqueModulePtr<PlatformIpcOperations> make_ipc_operations() const override;
54
55 EGLNativeDisplayType egl_native_display() const override;
56
57private:
58 EGLDeviceEXT device;
59 EGLDisplay display;
60 mir::Fd const drm_node;
61};
62}
63}
64}
65
66#endif // MIR_PLATFORMS_EGLSTREAM_KMS_PLATFORM_H_
067
=== added file 'src/platforms/eglstream-kms/server/platform_symbols.cpp'
--- src/platforms/eglstream-kms/server/platform_symbols.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/server/platform_symbols.cpp 2016-06-08 13:28:19 +0000
@@ -0,0 +1,189 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#include <epoxy/egl.h>
20
21#include "platform.h"
22#include "mir/graphics/platform.h"
23#include "mir/options/option.h"
24#include "mir/module_deleter.h"
25#include "mir/assert_module_entry_point.h"
26#include "mir/libname.h"
27#include "mir/log.h"
28#include "mir/graphics/egl_error.h"
29
30#include <boost/throw_exception.hpp>
31#include <boost/exception/diagnostic_information.hpp>
32#include <xf86drm.h>
33#include <sstream>
34
35#include <fcntl.h>
36
37namespace mg = mir::graphics;
38namespace mo = mir::options;
39namespace mge = mir::graphics::eglstream;
40
41mir::UniqueModulePtr<mg::Platform> create_host_platform(
42 std::shared_ptr<mo::Option> const& /*options*/,
43 std::shared_ptr<mir::EmergencyCleanupRegistry> const& emergency_cleanup_registry,
44 std::shared_ptr<mg::DisplayReport> const& report)
45{
46 mir::assert_entry_point_signature<mg::CreateHostPlatform>(&create_host_platform);
47
48 int device_count{0};
49 if (eglQueryDevicesEXT(0, nullptr, &device_count) != EGL_TRUE)
50 {
51 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to query device count with eglQueryDevicesEXT"));
52 }
53
54 auto devices = std::make_unique<EGLDeviceEXT[]>(device_count);
55 if (eglQueryDevicesEXT(device_count, devices.get(), &device_count) != EGL_TRUE)
56 {
57 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to get device list with eglQueryDevicesEXT"));
58 }
59
60 auto device = std::find_if(devices.get(), devices.get() + device_count,
61 [](EGLDeviceEXT device)
62 {
63 auto device_extensions = eglQueryDeviceStringEXT(device, EGL_EXTENSIONS);
64 if (device_extensions)
65 {
66 return strstr(device_extensions, "EGL_EXT_device_drm") != NULL;
67 }
68 return false;
69 });
70
71 if (device == (devices.get() + device_count))
72 {
73 BOOST_THROW_EXCEPTION(std::runtime_error("Couldn't find EGLDeviceEXT supporting EGL_EXT_device_drm?"));
74 }
75
76 return mir::make_module_ptr<mge::Platform>(*device, emergency_cleanup_registry, report);
77}
78
79void add_graphics_platform_options(boost::program_options::options_description& /*config*/)
80{
81 mir::assert_entry_point_signature<mg::AddPlatformOptions>(&add_graphics_platform_options);
82}
83
84mg::PlatformPriority probe_graphics_platform(mo::ProgramOption const& /*options*/)
85{
86 mir::assert_entry_point_signature<mg::PlatformProbe>(&probe_graphics_platform);
87
88 std::vector<char const*> missing_extensions;
89 for (char const* extension : {
90 "EGL_EXT_platform_base",
91 "EGL_EXT_platform_device",
92 "EGL_EXT_device_base",})
93 {
94 if (!epoxy_has_egl_extension(EGL_NO_DISPLAY, extension))
95 {
96 missing_extensions.push_back(extension);
97 }
98 }
99
100 if (!missing_extensions.empty())
101 {
102 std::stringstream message;
103 message << "Missing required extension" << (missing_extensions.size() > 1 ? "s:" : ":");
104 for (auto missing_extension : missing_extensions)
105 {
106 message << " " << missing_extension;
107 }
108
109 mir::log(
110 mir::logging::Severity::debug,
111 "platform-eglstream",
112 "EGLStream platform is unsupported: %s",
113 message.str().c_str());
114 return mg::PlatformPriority::unsupported;
115 }
116
117 int device_count{0};
118 if (eglQueryDevicesEXT(0, nullptr, &device_count) != EGL_TRUE)
119 {
120 mir::log(
121 mir::logging::Severity::informational,
122 "platform-eglstream",
123 "Platform claims to support EGL_EXT_device_base, but eglQueryDevicesEXT falied: %s",
124 mg::egl_category().message(eglGetError()).c_str());
125 return mg::PlatformPriority::unsupported;
126 }
127
128 auto devices = std::make_unique<EGLDeviceEXT[]>(device_count);
129 if (eglQueryDevicesEXT(device_count, devices.get(), &device_count) != EGL_TRUE)
130 {
131 BOOST_THROW_EXCEPTION(mg::egl_error("Failed to get device list with eglQueryDevicesEXT"));
132 }
133
134 if (std::none_of(devices.get(), devices.get() + device_count,
135 [](EGLDeviceEXT device)
136 {
137 auto device_extensions = eglQueryDeviceStringEXT(device, EGL_EXTENSIONS);
138 if (device_extensions)
139 {
140 mir::log(
141 mir::logging::Severity::debug,
142 "platform-eglstream",
143 "Found EGLDeviceEXT with device extensions: %s", device_extensions);
144 return strstr(device_extensions, "EGL_EXT_device_drm") != NULL;
145 }
146 else
147 {
148 mir::log(
149 mir::logging::Severity::debug,
150 "platform-eglstream",
151 "Found EGLDeviceEXT with no device extensions");
152 return false;
153 }
154 }))
155 {
156 mir::log(
157 mir::logging::Severity::debug,
158 "platform-eglstream",
159 "EGLDeviceEXTs found, but none support required EGL_EXT_device_drm extension");
160 return mg::PlatformPriority::unsupported;
161 }
162
163 return mg::PlatformPriority::best;
164}
165
166namespace
167{
168mir::ModuleProperties const description = {
169 "mir:eglstream-kms",
170 MIR_VERSION_MAJOR,
171 MIR_VERSION_MINOR,
172 MIR_VERSION_MICRO,
173 mir::libname()
174};
175}
176
177mir::ModuleProperties const* describe_graphics_module()
178{
179 mir::assert_entry_point_signature<mg::DescribeModule>(&describe_graphics_module);
180 return &description;
181}
182
183mir::UniqueModulePtr<mg::Platform> create_guest_platform(
184 std::shared_ptr<mg::DisplayReport> const&,
185 std::shared_ptr<mg::NestedContext> const& /*nested_context*/)
186{
187 mir::assert_entry_point_signature<mg::CreateGuestPlatform>(&create_guest_platform);
188 return nullptr;
189}
0190
=== added file 'src/platforms/eglstream-kms/server/symbols.map.in'
--- src/platforms/eglstream-kms/server/symbols.map.in 1970-01-01 00:00:00 +0000
+++ src/platforms/eglstream-kms/server/symbols.map.in 2016-06-08 13:28:19 +0000
@@ -0,0 +1,10 @@
1@MIR_SERVER_GRAPHICS_PLATFORM_VERSION@ {
2 global:
3 add_graphics_platform_options;
4 create_host_platform;
5 create_guest_platform;
6 probe_graphics_platform;
7 describe_graphics_module;
8 local:
9 *;
10};
011
=== modified file 'src/platforms/mesa/server/kms/platform_symbols.cpp'
--- src/platforms/mesa/server/kms/platform_symbols.cpp 2016-01-29 08:18:22 +0000
+++ src/platforms/mesa/server/kms/platform_symbols.cpp 2016-06-08 13:28:19 +0000
@@ -26,6 +26,7 @@
26#include "mir/assert_module_entry_point.h"26#include "mir/assert_module_entry_point.h"
27#include "mir/libname.h"27#include "mir/libname.h"
2828
29#include <EGL/egl.h>
29#include <fcntl.h>30#include <fcntl.h>
30#include <sys/ioctl.h>31#include <sys/ioctl.h>
3132
@@ -162,6 +163,19 @@
162 if (drm_devices.begin() == drm_devices.end())163 if (drm_devices.begin() == drm_devices.end())
163 return mg::PlatformPriority::unsupported;164 return mg::PlatformPriority::unsupported;
164165
166 // We also require GBM EGL platform
167 auto const* client_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
168 if (!client_extensions)
169 {
170 // Doesn't support EGL client extensions; Mesa does, so this is unlikely to be mesa.
171 return mg::PlatformPriority::unsupported;
172 }
173 if (strstr(client_extensions, "EGL_MESA_platform_gbm") == nullptr)
174 {
175 // No platform_gbm support, so we can't work.
176 return mg::PlatformPriority::unsupported;
177 }
178
165 // Check for master179 // Check for master
166 int tmp_fd = -1;180 int tmp_fd = -1;
167 for (auto& device : drm_devices)181 for (auto& device : drm_devices)
168182
=== modified file 'tests/unit-tests/CMakeLists.txt'
--- tests/unit-tests/CMakeLists.txt 2016-06-02 05:33:50 +0000
+++ tests/unit-tests/CMakeLists.txt 2016-06-08 13:28:19 +0000
@@ -17,6 +17,10 @@
17 add_definitions(-DMIR_BUILD_PLATFORM_MESA_X11)17 add_definitions(-DMIR_BUILD_PLATFORM_MESA_X11)
18endif()18endif()
1919
20if (MIR_BUILD_PLATFORM_EGLSTREAM_KMS)
21 add_definitions(-DMIR_BUILD_PLATFORM_EGLSTREAM_KMS)
22endif()
23
20include_directories(24include_directories(
21 ${CMAKE_SOURCE_DIR}25 ${CMAKE_SOURCE_DIR}
2226
2327
=== modified file 'tests/unit-tests/client/test_probing_client_platform_factory.cpp'
--- tests/unit-tests/client/test_probing_client_platform_factory.cpp 2016-05-27 00:47:04 +0000
+++ tests/unit-tests/client/test_probing_client_platform_factory.cpp 2016-06-08 13:28:19 +0000
@@ -55,6 +55,13 @@
55 memset(&pkg, 0, sizeof(pkg));55 memset(&pkg, 0, sizeof(pkg));
56}56}
5757
58#if defined(MIR_BUILD_PLATFORM_EGLSTREAM_KMS)
59void populate_valid_eglstream_platform_package(MirPlatformPackage& pkg)
60{
61 memset(&pkg, 0, sizeof(pkg));
62}
63#endif
64
58class ModuleContext65class ModuleContext
59{66{
60public:67public:
@@ -115,6 +122,11 @@
115 std::make_pair<std::string, ModuleContext>(122 std::make_pair<std::string, ModuleContext>(
116 "android", { "android", "graphics-android", &populate_valid_android_platform_package }));123 "android", { "android", "graphics-android", &populate_valid_android_platform_package }));
117#endif124#endif
125#if defined(MIR_BUILD_PLATFORM_EGLSTREAM_KMS)
126 modules.emplace(
127 std::make_pair<std::string, ModuleContext>(
128 "eglstream-kms", { "eglstream", "graphics-eglstream-kms", &populate_valid_eglstream_platform_package}));
129#endif
118 return modules;130 return modules;
119}131}
120132
@@ -289,6 +301,26 @@
289 EXPECT_EQ(mir_platform_type_gbm, platform->platform_type());301 EXPECT_EQ(mir_platform_type_gbm, platform->platform_type());
290}302}
291303
304#if defined(MIR_BUILD_PLATFORM_EGLSTREAM_KMS)
305TEST(ProbingClientPlatformFactory, CreatesEglstreamPlatformOnEglstreamKMS)
306#else
307TEST(ProbingClientPlatformFactory, DISABLED_CreatesEglstreamPlatformOnEglstreamKMS)
308#endif
309{
310 using namespace testing;
311
312 mir::client::ProbingClientPlatformFactory factory(
313 mir::report::null_shared_library_prober_report(),
314 all_available_modules(),
315 {});
316
317 NiceMock<mtd::MockClientContext> context;
318 all_available_fixtures().at("eglstream-kms").setup_context(context);
319
320 auto platform = factory.create_client_platform(&context);
321 EXPECT_EQ(mir_platform_type_eglstream, platform->platform_type());
322}
323
292#ifdef MIR_BUILD_PLATFORM_ANDROID324#ifdef MIR_BUILD_PLATFORM_ANDROID
293TEST(ProbingClientPlatformFactory, CreatesAndroidPlatformWhenAppropriate)325TEST(ProbingClientPlatformFactory, CreatesAndroidPlatformWhenAppropriate)
294#else326#else
295327
=== modified file 'tests/unit-tests/graphics/mesa/kms/test_platform.cpp'
--- tests/unit-tests/graphics/mesa/kms/test_platform.cpp 2016-01-29 08:18:22 +0000
+++ tests/unit-tests/graphics/mesa/kms/test_platform.cpp 2016-06-08 13:28:19 +0000
@@ -40,6 +40,7 @@
4040
41#include "mir/test/doubles/mock_drm.h"41#include "mir/test/doubles/mock_drm.h"
42#include "mir/test/doubles/mock_gbm.h"42#include "mir/test/doubles/mock_gbm.h"
43#include "mir/test/doubles/mock_egl.h"
43#include "mir/test/doubles/fd_matcher.h"44#include "mir/test/doubles/fd_matcher.h"
4445
45#include <gtest/gtest.h>46#include <gtest/gtest.h>
@@ -65,8 +66,11 @@
65public:66public:
66 void SetUp()67 void SetUp()
67 {68 {
68 ::testing::Mock::VerifyAndClearExpectations(&mock_drm);69 using namespace testing;
69 ::testing::Mock::VerifyAndClearExpectations(&mock_gbm);70 Mock::VerifyAndClearExpectations(&mock_drm);
71 Mock::VerifyAndClearExpectations(&mock_gbm);
72 ON_CALL(mock_egl, eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS))
73 .WillByDefault(Return("EGL_AN_extension_string EGL_MESA_platform_gbm"));
70 fake_devices.add_standard_device("standard-drm-devices");74 fake_devices.add_standard_device("standard-drm-devices");
71 }75 }
7276
@@ -81,6 +85,7 @@
8185
82 ::testing::NiceMock<mtd::MockDRM> mock_drm;86 ::testing::NiceMock<mtd::MockDRM> mock_drm;
83 ::testing::NiceMock<mtd::MockGBM> mock_gbm;87 ::testing::NiceMock<mtd::MockGBM> mock_gbm;
88 ::testing::NiceMock<mtd::MockEGL> mock_egl;
84 mtf::UdevEnvironment fake_devices;89 mtf::UdevEnvironment fake_devices;
85};90};
86}91}
@@ -366,3 +371,43 @@
366 auto probe = platform_lib.load_function<mg::PlatformProbe>(probe_platform);371 auto probe = platform_lib.load_function<mg::PlatformProbe>(probe_platform);
367 EXPECT_EQ(mg::PlatformPriority::best, probe(options));372 EXPECT_EQ(mg::PlatformPriority::best, probe(options));
368}373}
374
375TEST_F(MesaGraphicsPlatform, probe_returns_unsupported_when_egl_client_extensions_not_supported)
376{
377 using namespace testing;
378
379 mtf::UdevEnvironment udev_environment;
380 boost::program_options::options_description po;
381 mir::options::ProgramOption options;
382 const char *argv[] = {"dummy", "--vt"};
383 options.parse_arguments(po, 2, argv);
384
385 udev_environment.add_standard_device("standard-drm-devices");
386
387 ON_CALL(mock_egl, eglQueryString(EGL_NO_DISPLAY, _))
388 .WillByDefault(Return(nullptr));
389
390 mir::SharedLibrary platform_lib{mtf::server_platform("graphics-mesa-kms")};
391 auto probe = platform_lib.load_function<mg::PlatformProbe>(probe_platform);
392 EXPECT_EQ(mg::PlatformPriority::unsupported, probe(options));
393}
394
395TEST_F(MesaGraphicsPlatform, probe_returns_unsupported_when_gbm_platform_not_supported)
396{
397 using namespace testing;
398
399 mtf::UdevEnvironment udev_environment;
400 boost::program_options::options_description po;
401 mir::options::ProgramOption options;
402 const char *argv[] = {"dummy", "--vt"};
403 options.parse_arguments(po, 2, argv);
404
405 udev_environment.add_standard_device("standard-drm-devices");
406
407 ON_CALL(mock_egl, eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS))
408 .WillByDefault(Return("EGL_KHR_not_really_an_extension EGL_EXT_master_of_the_house"));
409
410 mir::SharedLibrary platform_lib{mtf::server_platform("graphics-mesa-kms")};
411 auto probe = platform_lib.load_function<mg::PlatformProbe>(probe_platform);
412 EXPECT_EQ(mg::PlatformPriority::unsupported, probe(options));
413}
369414
=== modified file 'tests/unit-tests/graphics/test_platform_prober.cpp'
--- tests/unit-tests/graphics/test_platform_prober.cpp 2016-05-27 03:32:07 +0000
+++ tests/unit-tests/graphics/test_platform_prober.cpp 2016-06-08 13:28:19 +0000
@@ -27,6 +27,7 @@
27#ifdef MIR_BUILD_PLATFORM_MESA_KMS27#ifdef MIR_BUILD_PLATFORM_MESA_KMS
28#include "mir/test/doubles/mock_drm.h"28#include "mir/test/doubles/mock_drm.h"
29#include "mir/test/doubles/mock_gbm.h"29#include "mir/test/doubles/mock_gbm.h"
30#include "mir/test/doubles/mock_egl.h"
30#endif31#endif
3132
32#ifdef MIR_BUILD_PLATFORM_ANDROID33#ifdef MIR_BUILD_PLATFORM_ANDROID
@@ -81,11 +82,18 @@
8182
82std::shared_ptr<void> ensure_mesa_probing_succeeds()83std::shared_ptr<void> ensure_mesa_probing_succeeds()
83{84{
84 auto udev = std::make_shared<mtf::UdevEnvironment>();85 using namespace testing;
8586 struct MockEnvironment {
86 udev->add_standard_device("standard-drm-devices");87 mtf::UdevEnvironment udev;
8788 mtd::MockEGL egl;
88 return udev;89 };
90 auto env = std::make_shared<MockEnvironment>();
91
92 env->udev.add_standard_device("standard-drm-devices");
93 ON_CALL(env->egl, eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS))
94 .WillByDefault(Return("EGL_MESA_platform_gbm"));
95
96 return env;
89}97}
9098
91std::shared_ptr<void> ensure_android_probing_succeeds()99std::shared_ptr<void> ensure_android_probing_succeeds()
@@ -236,7 +244,7 @@
236 auto descriptor = module->load_function<mir::graphics::DescribeModule>(describe_module);244 auto descriptor = module->load_function<mir::graphics::DescribeModule>(describe_module);
237 auto description = descriptor();245 auto description = descriptor();
238246
239 EXPECT_THAT(description->name, Not(HasSubstr("dummy")));247 EXPECT_THAT(description->name, Not(HasSubstr("mir:stub-graphics")));
240}248}
241#endif249#endif
242250

Subscribers

People subscribed via source and target branches