Mir

Merge lp:~raof/mir/require-egl-extensions into lp:mir

Proposed by Chris Halse Rogers
Status: Work in progress
Proposed branch: lp:~raof/mir/require-egl-extensions
Merge into: lp:mir
Diff against target: 329 lines (+240/-1)
9 files modified
CMakeLists.txt (+1/-0)
src/include/platform/mir/graphics/require_egl_extensions.h (+44/-0)
src/platform/CMakeLists.txt (+1/-0)
src/platform/graphics/CMakeLists.txt (+6/-1)
src/platform/graphics/require_egl_extensions.cpp (+53/-0)
src/platform/symbols.map (+7/-0)
tests/mir_test_doubles/mock_egl.cpp (+25/-0)
tests/unit-tests/graphics/CMakeLists.txt (+1/-0)
tests/unit-tests/graphics/test_require_egl_extensions.cpp (+102/-0)
To merge this branch: bzr merge lp:~raof/mir/require-egl-extensions
Reviewer Review Type Date Requested Status
Cemil Azizoglu (community) Approve
Mir CI Bot continuous-integration Needs Fixing
Review via email: mp+293709@code.launchpad.net

Commit message

Add mg::require_egl_extensions.

A helper function that takes a list of EGL extension strings and a display, checks whether or not they are all supported or throws an exception containing the list of unsupported extensions.

Description of the change

Add mg::require_egl_extensions.

A helper function that takes a list of EGL extension strings and a display, checks whether or not they are all supported or throws an exception containing the list of unsupported extensions.

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
Daniel van Vugt (vanvugt) wrote :

Wait, libepoxy is the helper function. Why do we need to wrap the helper functions in more helper functions?

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

Because I got bored manually checking epoxy_has_extension() and accumulating the results in a couple of different places.

It's also nice if your exception message contains *all* the missing extensions, rather than the first one you hit.

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

Oh, yeah. I probably need to make Mir depend on libepoxy-dev if I'm going to use it...

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

Ok

Nit :
A bit out of place here
+ ${PROJECT_SOURCE_DIR}/src/include/platform/mir/graphics/require_egl_extensions.h

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

I'm no longer sure if I'll end up using this, so WIP for now.

Unmerged revisions

3497. By Chris Halse Rogers

Document what mg::require_egl_extensions does

3496. By Chris Halse Rogers

Add mg::require_egl_extensions.

This provides a convenient way of asserting that a list of extensions are supported.

3495. By Chris Halse Rogers

MockEGL: wrap dlopen() to hook libraries that grab libEGL themselves.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2016-05-03 04:36:33 +0000
3+++ CMakeLists.txt 2016-05-04 04:43:00 +0000
4@@ -194,6 +194,7 @@
5 find_package(LTTngUST REQUIRED)
6 pkg_check_modules(UDEV REQUIRED libudev)
7 pkg_check_modules(GLIB REQUIRED glib-2.0)
8+pkg_check_modules(EPOXY REQUIRED epoxy)
9
10 include_directories (SYSTEM ${GLESv2_INCLUDE_DIRS})
11 include_directories (SYSTEM ${EGL_INCLUDE_DIRS})
12
13=== added file 'src/include/platform/mir/graphics/require_egl_extensions.h'
14--- src/include/platform/mir/graphics/require_egl_extensions.h 1970-01-01 00:00:00 +0000
15+++ src/include/platform/mir/graphics/require_egl_extensions.h 2016-05-04 04:43:00 +0000
16@@ -0,0 +1,44 @@
17+/*
18+ * Copyright © 2016 Canonical Ltd.
19+ *
20+ * This program is free software: you can redistribute it and/or modify it
21+ * under the terms of the GNU Lesser General Public License version 3,
22+ * as published by the Free Software Foundation.
23+ *
24+ * This program is distributed in the hope that it will be useful,
25+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
26+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27+ * GNU Lesser General Public License for more details.
28+ *
29+ * You should have received a copy of the GNU Lesser General Public License
30+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
31+ *
32+ * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
33+ */
34+#ifndef MIR_GRAPHICS_REQUIRE_EGL_EXTENSIONS_H_
35+#define MIR_GRAPHICS_REQUIRE_EGL_EXTENSIONS_H_
36+
37+#include <initializer_list>
38+
39+// Manually define EGLDisplay to avoid needing to pull epoxy header in here
40+#ifndef EGLDisplay
41+typedef void* EGLDisplay;
42+#endif
43+
44+namespace mir
45+{
46+namespace graphics
47+{
48+/**
49+ * Check that dpy supports all of extensions.
50+ *
51+ * \param [in] dpy The EGLDisplay to query (or EGL_NO_DISPLAY for EGL client extensions)
52+ * \param [in] extensions The list of EGL extensions to check for
53+ * \throw A std::runtime_error if any extension in extensions is not supported. The exception
54+ * description will include a list of all the unsupported extensions.
55+ */
56+void require_egl_extensions(EGLDisplay dpy, std::initializer_list<char const*> const& extensions);
57+}
58+}
59+
60+#endif //MIR_GRAPHICS_REQUIRE_EGL_EXTENSIONS_H_
61
62=== modified file 'src/platform/CMakeLists.txt'
63--- src/platform/CMakeLists.txt 2016-01-29 08:18:22 +0000
64+++ src/platform/CMakeLists.txt 2016-05-04 04:43:00 +0000
65@@ -19,6 +19,7 @@
66 set(MIR_PLATFORM_REFERENCES
67 ${EGL_LDFLAGS} ${EGL_LIBRARIES}
68 ${GLESv2_LDFLAGS} ${GLESv2_LIBRARIES}
69+ ${EPOXY_LDFLAGS} ${EPOXY_LIBRARIES}
70 )
71
72 add_subdirectory(graphics/)
73
74=== modified file 'src/platform/graphics/CMakeLists.txt'
75--- src/platform/graphics/CMakeLists.txt 2016-03-29 07:30:50 +0000
76+++ src/platform/graphics/CMakeLists.txt 2016-05-04 04:43:00 +0000
77@@ -1,4 +1,7 @@
78-include_directories(${GLESv2_INCLUDE_DIRS})
79+include_directories(
80+ ${GLESv2_INCLUDE_DIRS}
81+ ${EPOXY_INCLUDE_DIRS}
82+)
83
84 set(
85 GRAPHICS_SOURCES
86@@ -11,6 +14,8 @@
87 pixel_format_utils.cpp
88 overlapping_output_grouping.cpp
89 platform_probe.cpp
90+ ${PROJECT_SOURCE_DIR}/src/include/platform/mir/graphics/require_egl_extensions.h
91+ require_egl_extensions.cpp
92 )
93
94 add_library(mirplatformgraphicscommon OBJECT
95
96=== added file 'src/platform/graphics/require_egl_extensions.cpp'
97--- src/platform/graphics/require_egl_extensions.cpp 1970-01-01 00:00:00 +0000
98+++ src/platform/graphics/require_egl_extensions.cpp 2016-05-04 04:43:00 +0000
99@@ -0,0 +1,53 @@
100+/*
101+ * Copyright © 2016 Canonical Ltd.
102+ *
103+ * This program is free software: you can redistribute it and/or modify it
104+ * under the terms of the GNU Lesser General Public License version 3,
105+ * as published by the Free Software Foundation.
106+ *
107+ * This program is distributed in the hope that it will be useful,
108+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
109+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
110+ * GNU Lesser General Public License for more details.
111+ *
112+ * You should have received a copy of the GNU Lesser General Public License
113+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
114+ *
115+ * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
116+ */
117+
118+#include "mir/graphics/require_egl_extensions.h"
119+
120+#include <epoxy/egl.h>
121+
122+#include <stdexcept>
123+#include <vector>
124+#include <sstream>
125+#include <boost/throw_exception.hpp>
126+
127+namespace mg = mir::graphics;
128+
129+void mg::require_egl_extensions(
130+ EGLDisplay dpy,
131+ std::initializer_list<char const*> const& extensions)
132+{
133+ using namespace std::string_literals;
134+ std::vector<char const*> missing_extensions;
135+ for (auto extension : extensions)
136+ {
137+ if (!epoxy_has_egl_extension(dpy, extension))
138+ {
139+ missing_extensions.push_back(extension);
140+ }
141+ }
142+ if (!missing_extensions.empty())
143+ {
144+ std::stringstream exception_message;
145+ exception_message << "Missing required extension" << (missing_extensions.size() > 1 ? "s:" : ":");
146+ for (auto missing_extension : missing_extensions)
147+ {
148+ exception_message << " " << missing_extension;
149+ }
150+ BOOST_THROW_EXCEPTION(std::runtime_error{exception_message.str()});
151+ }
152+}
153
154=== modified file 'src/platform/symbols.map'
155--- src/platform/symbols.map 2016-03-29 07:30:50 +0000
156+++ src/platform/symbols.map 2016-05-04 04:43:00 +0000
157@@ -288,3 +288,10 @@
158 mir::udev::Context::ctx*;
159 };
160 } MIRPLATFORM_11;
161+
162+MIR_PLATFORM_0.24 {
163+ global:
164+ extern "C++" {
165+ mir::graphics::require_egl_extensions*;
166+ };
167+} MIR_PLATFORM_0.21;
168
169=== modified file 'tests/mir_test_doubles/mock_egl.cpp'
170--- tests/mir_test_doubles/mock_egl.cpp 2016-01-29 08:18:22 +0000
171+++ tests/mir_test_doubles/mock_egl.cpp 2016-05-04 04:43:00 +0000
172@@ -21,6 +21,7 @@
173 #include "mir/egl_native_surface.h"
174
175 #include "mir/test/doubles/mock_egl.h"
176+#include <dlfcn.h>
177 #include <gtest/gtest.h>
178
179 namespace mtd = mir::test::doubles;
180@@ -198,6 +199,30 @@
181 return; \
182 }
183
184+/*
185+ * libepoxy will try and dlopen libEGL.so.1, so we have to
186+ * wrap dlopen() and return the main executable for EGL
187+ */
188+void* dlopen(char const* filename, int flags) __THROWNL
189+{
190+ static void* (*real_dlopen)(char const*, int) = nullptr;
191+
192+ if (real_dlopen == nullptr)
193+ {
194+ real_dlopen =
195+ reinterpret_cast<void*(*)(char const*, int)>(dlsym(RTLD_NEXT, "dlopen"));
196+ }
197+
198+ if (strcmp(filename, "libEGL.so.1") == 0)
199+ {
200+ return real_dlopen(NULL, flags);
201+ }
202+ else
203+ {
204+ return real_dlopen(filename, flags);
205+ }
206+}
207+
208 EGLint eglGetError (void)
209 {
210 CHECK_GLOBAL_MOCK(EGLint)
211
212=== modified file 'tests/unit-tests/graphics/CMakeLists.txt'
213--- tests/unit-tests/graphics/CMakeLists.txt 2016-05-03 04:36:33 +0000
214+++ tests/unit-tests/graphics/CMakeLists.txt 2016-05-04 04:43:00 +0000
215@@ -10,6 +10,7 @@
216 ${CMAKE_CURRENT_SOURCE_DIR}/test_overlapping_output_grouping.cpp
217 ${CMAKE_CURRENT_SOURCE_DIR}/test_software_cursor.cpp
218 ${CMAKE_CURRENT_SOURCE_DIR}/test_anonymous_shm_file.cpp
219+ ${CMAKE_CURRENT_SOURCE_DIR}/test_require_egl_extensions.cpp
220 )
221
222
223
224=== added file 'tests/unit-tests/graphics/test_require_egl_extensions.cpp'
225--- tests/unit-tests/graphics/test_require_egl_extensions.cpp 1970-01-01 00:00:00 +0000
226+++ tests/unit-tests/graphics/test_require_egl_extensions.cpp 2016-05-04 04:43:00 +0000
227@@ -0,0 +1,102 @@
228+/*
229+ * Copyright © 2016 Canonical Ltd.
230+ *
231+ * This program is free software: you can redistribute it and/or modify it
232+ * under the terms of the GNU General Public License version 3,
233+ * as published by the Free Software Foundation.
234+ *
235+ * This program is distributed in the hope that it will be useful,
236+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
237+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
238+ * GNU General Public License for more details.
239+ *
240+ * You should have received a copy of the GNU General Public License
241+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
242+ *
243+ * Authored by:
244+ * Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
245+ */
246+
247+#include "mir/graphics/require_egl_extensions.h"
248+#include "mir/test/doubles/mock_egl.h"
249+#include <stdexcept>
250+
251+#include <gtest/gtest.h>
252+#include <gmock/gmock.h>
253+
254+namespace mg = mir::graphics;
255+namespace mtd = mir::test::doubles;
256+using namespace testing;
257+
258+typedef mtd::MockEGL::generic_function_pointer_t func_ptr_t;
259+class RequireEglExtensions : public ::testing::Test
260+{
261+protected:
262+ virtual void SetUp()
263+ {
264+ }
265+
266+ testing::NiceMock<mtd::MockEGL> mock_egl;
267+};
268+
269+TEST_F(RequireEglExtensions, succeeds_if_all_extensions_are_found)
270+{
271+ ON_CALL(mock_egl, eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS))
272+ .WillByDefault(
273+ Return("EGL_EXT_platform_base EGL_EXT_platform_device EGL_EXT_device_base"));
274+
275+ mg::require_egl_extensions(EGL_NO_DISPLAY, {
276+ "EGL_EXT_platform_base",
277+ "EGL_EXT_platform_device",
278+ "EGL_EXT_device_base"
279+ });
280+}
281+
282+TEST_F(RequireEglExtensions, succeeds_if_all_client_extensions_are_found)
283+{
284+ ON_CALL(mock_egl, eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS))
285+ .WillByDefault(
286+ Return("EGL_EXT_platform_base EGL_EXT_platform_device EGL_EXT_device_base"));
287+
288+ mg::require_egl_extensions(EGL_NO_DISPLAY, {
289+ "EGL_EXT_platform_base",
290+ "EGL_EXT_platform_device",
291+ "EGL_EXT_device_base"
292+ });
293+}
294+
295+TEST_F(RequireEglExtensions, succeeds_if_all_display_extensions_are_found)
296+{
297+ EGLDisplay dummy = reinterpret_cast<EGLDisplay>(0xdeadbeef);
298+ ON_CALL(mock_egl, eglQueryString(dummy, EGL_EXTENSIONS))
299+ .WillByDefault(
300+ Return("EGL_KHR_image EGL_KHR_image_base EGL_KHR_reusable_sync EGL_KHR_stream"));
301+
302+ mg::require_egl_extensions(dummy, {
303+ "EGL_KHR_image",
304+ "EGL_KHR_image_base",
305+ });
306+}
307+
308+TEST_F(RequireEglExtensions, fails_with_list_of_unsupported_extensions)
309+{
310+ ON_CALL(mock_egl, eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS))
311+ .WillByDefault(Return("EGL_EXT_device_base"));
312+
313+ auto required_extensions = {
314+ "EGL_EXT_platform_base",
315+ "EGL_EXT_device_base",
316+ "EGL_EXT_platform_device",
317+ };
318+ try
319+ {
320+ mg::require_egl_extensions(EGL_NO_DISPLAY, required_extensions);
321+ }
322+ catch (std::runtime_error const& err)
323+ {
324+ EXPECT_THAT(err.what(), AllOf(HasSubstr("EGL_EXT_platform_base"), HasSubstr("EGL_EXT_platform_device")));
325+ return;
326+ }
327+
328+ FAIL() << "require_egl_extensions unexpectedly succeeded";
329+}

Subscribers

People subscribed via source and target branches