Skip to content

Commit

Permalink
Merge #730
Browse files Browse the repository at this point in the history
730: mesa-kms: Use EGL_EXT_platform_base. r=AlanGriffiths a=RAOF

This lets us explicitly ask for a GBM-backed EGL platform, rather than just hoping
the libEGL can correctly guess what we've handed in is a pointer to a `gbm_device`.

This is necessary for Mali support, as Mali's libEGL will *not* guess that what
you've passed in to `eglGetDisplay()` is a `gbm_device*`.

Co-authored-by: Christopher James Halse Rogers <[email protected]>
  • Loading branch information
2 people authored and AlanGriffiths committed Feb 18, 2019
1 parent 09e0052 commit 8b44db3
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 11 deletions.
8 changes: 8 additions & 0 deletions include/platform/mir/graphics/egl_extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ struct EGLExtensions
PFNEGLCREATESTREAMATTRIBNVPROC const eglCreateStreamAttribNV;
PFNEGLSTREAMCONSUMERACQUIREATTRIBNVPROC const eglStreamConsumerAcquireAttribNV;
};
struct PlatformBaseEXT
{
PlatformBaseEXT();

PFNEGLGETPLATFORMDISPLAYEXTPROC const eglGetPlatformDisplay;
PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC const eglCreatePlatformWindowSurface;
};
std::experimental::optional<PlatformBaseEXT> const platform_base;
};

}
Expand Down
3 changes: 3 additions & 0 deletions include/test/mir/test/doubles/mock_egl.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,15 @@ class MockEGL
MOCK_METHOD1(eglBindApi, EGLBoolean(EGLenum));
MOCK_METHOD1(eglGetProcAddress,generic_function_pointer_t(const char*));

MOCK_METHOD3(eglGetPlatformDisplayEXT, EGLDisplay(EGLenum, AnyNativeType, EGLint const*));

// Config management
MOCK_METHOD4(eglGetConfigs, EGLBoolean(EGLDisplay,EGLConfig*,EGLint,EGLint*));
MOCK_METHOD5(eglChooseConfig, EGLBoolean(EGLDisplay, const EGLint*,EGLConfig*,EGLint,EGLint*));
MOCK_METHOD4(eglGetConfigAttrib, EGLBoolean(EGLDisplay,EGLConfig,EGLint,EGLint*));

// Surface management
MOCK_METHOD4(eglCreatePlatformWindowSurfaceEXT, EGLSurface(EGLDisplay,EGLConfig,AnyNativeType, EGLint const*));
MOCK_METHOD4(eglCreateWindowSurface, EGLSurface(EGLDisplay,EGLConfig,AnyNativeType,const EGLint*));
MOCK_METHOD4(eglCreatePixmapSurface, EGLSurface(EGLDisplay,EGLConfig,AnyNativeType,const EGLint*));
MOCK_METHOD3(eglCreatePbufferSurface, EGLSurface(EGLDisplay,EGLConfig,const EGLint*));
Expand Down
35 changes: 34 additions & 1 deletion src/platform/graphics/egl_extensions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "mir/graphics/egl_extensions.h"
#include <boost/throw_exception.hpp>
#include <stdexcept>
#include <cstring>

#define MIR_LOG_COMPONENT "EGL extensions"
#include "mir/log.h"
Expand All @@ -39,6 +40,18 @@ std::experimental::optional<mg::EGLExtensions::WaylandExtensions> maybe_wayland_
return {};
}
}

std::experimental::optional<mg::EGLExtensions::PlatformBaseEXT> maybe_platform_base_ext()
{
try
{
return mg::EGLExtensions::PlatformBaseEXT{};
}
catch (std::runtime_error const&)
{
return {};
}
}
}

mg::EGLExtensions::EGLExtensions() :
Expand All @@ -55,7 +68,8 @@ mg::EGLExtensions::EGLExtensions() :
*/
glEGLImageTargetTexture2DOES{
reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"))},
wayland{maybe_wayland_ext()}
wayland{maybe_wayland_ext()},
platform_base{maybe_platform_base_ext()}
{
if (!eglCreateImageKHR || !eglDestroyImageKHR)
BOOST_THROW_EXCEPTION(std::runtime_error("EGL implementation doesn't support EGLImage"));
Expand Down Expand Up @@ -92,3 +106,22 @@ mg::EGLExtensions::NVStreamAttribExtensions::NVStreamAttribExtensions() :
BOOST_THROW_EXCEPTION((std::runtime_error{"EGL implementation doesn't support EGL_NV_stream_attrib"}));
}
}

mg::EGLExtensions::PlatformBaseEXT::PlatformBaseEXT()
: eglGetPlatformDisplay{
reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"))
},
eglCreatePlatformWindowSurface{
reinterpret_cast<PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC>(
eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT"))
}
{
auto const* client_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
if (!client_extensions ||
!strstr(client_extensions, "EGL_EXT_platform_base") ||
!eglGetPlatformDisplay ||
!eglCreatePlatformWindowSurface)
{
BOOST_THROW_EXCEPTION((std::runtime_error{"EGL implementation doesn't support EGL_EXT_platform_base"}));
}
}
7 changes: 7 additions & 0 deletions src/platform/symbols.map
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,10 @@ MIR_PLATFORM_1.1.0 {
mir::graphics::EGLExtensions::NVStreamAttribExtensions::NVStreamAttribExtensions*;
};
} MIR_PLATFORM_0.32.3;

MIR_PLATFORM_1.1.1 {
global:
extern "C++" {
mir::graphics::EGLExtensions::PlatformBaseEXT*;
};
} MIR_PLATFORM_1.1.0;
1 change: 1 addition & 0 deletions src/platforms/mesa/server/buffer_allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ class WaylandTexBuffer :

const EGLint image_attrs[] =
{
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
EGL_WAYLAND_PLANE_WL, 0,
EGL_NONE
};
Expand Down
11 changes: 9 additions & 2 deletions src/platforms/mesa/server/kms/egl_helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,11 @@ void mgmh::EGLHelper::setup(GBMHelper const& gbm, gbm_surface* surface_gbm,
// TODO: Take the required format as a parameter, so we can select the framebuffer format.
setup_internal(gbm, false, GBM_FORMAT_XRGB8888);

egl_surface = eglCreateWindowSurface(egl_display, egl_config, surface_gbm, nullptr);
egl_surface = platform_base.eglCreatePlatformWindowSurface(
egl_display,
egl_config,
surface_gbm,
nullptr);
if(egl_surface == EGL_NO_SURFACE)
BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL window surface"));

Expand Down Expand Up @@ -204,7 +208,10 @@ void mgmh::EGLHelper::setup_internal(GBMHelper const& gbm, bool initialize, EGLi
static const EGLint required_egl_version_major = 1;
static const EGLint required_egl_version_minor = 4;

egl_display = eglGetDisplay(static_cast<EGLNativeDisplayType>(gbm.device));
egl_display = platform_base.eglGetPlatformDisplay(
EGL_PLATFORM_GBM_KHR, // EGL_PLATFORM_GBM_MESA has the same value.
static_cast<EGLNativeDisplayType>(gbm.device),
nullptr);
if (egl_display == EGL_NO_DISPLAY)
BOOST_THROW_EXCEPTION(mg::egl_error("Failed to get EGL display"));

Expand Down
2 changes: 2 additions & 0 deletions src/platforms/mesa/server/kms/egl_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#define MIR_GRAPHICS_MESA_EGL_HELPER_H_

#include "display_helpers.h"
#include "mir/graphics/egl_extensions.h"
#include <EGL/egl.h>

namespace mir
Expand Down Expand Up @@ -68,6 +69,7 @@ class EGLHelper
EGLContext egl_context;
EGLSurface egl_surface;
bool should_terminate_egl;
EGLExtensions::PlatformBaseEXT platform_base;
};
}
}
Expand Down
47 changes: 46 additions & 1 deletion tests/mir_test_doubles/mock_egl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ EGLBoolean extension_eglQueryWaylandBufferWL(
EGLDisplay dpy,
struct wl_resource *buffer,
EGLint attribute, EGLint *value);
EGLDisplay extension_eglGetPlatformDisplayEXT(
EGLenum platform,
void *native_display,
const EGLint *attrib_list);
EGLSurface extension_eglCreatePlatformWindowSurfaceEXT(
EGLDisplay dpy,
EGLConfig config,
void *native_window,
const EGLint *attrib_list);

/* EGL{Surface,Display,Config,Context} are all opaque types, so we can put whatever
we want in them for testing */
Expand All @@ -80,6 +89,8 @@ mtd::MockEGL::MockEGL()

ON_CALL(*this, eglGetDisplay(_))
.WillByDefault(Return(fake_egl_display));
ON_CALL(*this, eglGetPlatformDisplayEXT(_,_,_))
.WillByDefault(Return(fake_egl_display));
ON_CALL(*this, eglInitialize(_,_,_))
.WillByDefault(DoAll(
SetArgPointee<1>(1),
Expand Down Expand Up @@ -118,6 +129,8 @@ mtd::MockEGL::MockEGL()

ON_CALL(*this, eglCreateWindowSurface(_,_,_,_))
.WillByDefault(Return(fake_egl_surface));
ON_CALL(*this, eglCreatePlatformWindowSurfaceEXT(_,_,_,_))
.WillByDefault(Return(fake_egl_surface));

ON_CALL(*this, eglCreatePbufferSurface(_,_,_))
.WillByDefault(Return(fake_egl_surface));
Expand Down Expand Up @@ -173,6 +186,10 @@ mtd::MockEGL::MockEGL()
.WillByDefault(Return(reinterpret_cast<func_ptr_t>(&extension_eglBindWaylandDisplayWL)));
ON_CALL(*this, eglGetProcAddress(StrEq("eglUnbindWaylandDisplayWL")))
.WillByDefault(Return(reinterpret_cast<func_ptr_t>(&extension_eglUnbindWaylandDisplayWL)));
ON_CALL(*this, eglGetProcAddress(StrEq("eglGetPlatformDisplayEXT")))
.WillByDefault(Return(reinterpret_cast<func_ptr_t>(&extension_eglGetPlatformDisplayEXT)));
ON_CALL(*this, eglGetProcAddress(StrEq("eglCreatePlatformWindowSurfaceEXT")))
.WillByDefault(Return(reinterpret_cast<func_ptr_t>(&extension_eglCreatePlatformWindowSurfaceEXT)));
}

void mtd::MockEGL::provide_egl_extensions()
Expand All @@ -184,7 +201,8 @@ void mtd::MockEGL::provide_egl_extensions()
"EGL_KHR_image_base "
"EGL_KHR_image_pixmap "
"EGL_EXT_image_dma_buf_import "
"EGL_WL_bind_wayland_display";
"EGL_WL_bind_wayland_display "
"EGL_EXT_platform_base";
ON_CALL(*this, eglQueryString(_,EGL_EXTENSIONS))
.WillByDefault(Return(egl_exts));
}
Expand Down Expand Up @@ -484,3 +502,30 @@ EGLBoolean extension_eglQueryWaylandBufferWL(
return global_mock_egl->eglQueryWaylandBufferWL(
dpy, buffer, attribute, value);
}


EGLDisplay extension_eglGetPlatformDisplayEXT(
EGLenum platform,
void *native_display,
const EGLint *attrib_list)
{
CHECK_GLOBAL_MOCK(EGLDisplay);
return global_mock_egl->eglGetPlatformDisplayEXT(
platform,
native_display,
attrib_list);
}

EGLSurface extension_eglCreatePlatformWindowSurfaceEXT(
EGLDisplay dpy,
EGLConfig config,
void *native_window,
const EGLint *attrib_list)
{
CHECK_GLOBAL_MOCK(EGLSurface);
return global_mock_egl->eglCreatePlatformWindowSurfaceEXT(
dpy,
config,
native_window,
attrib_list);
}
2 changes: 1 addition & 1 deletion tests/unit-tests/graphics/test_platform_prober.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ std::shared_ptr<void> ensure_mesa_probing_succeeds()

env->udev.add_standard_device("standard-drm-devices");
ON_CALL(env->egl, eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS))
.WillByDefault(Return("EGL_MESA_platform_gbm"));
.WillByDefault(Return("EGL_MESA_platform_gbm EGL_EXT_platform_base"));
ON_CALL(env->gbm, gbm_create_device(_))
.WillByDefault(Return(fake_gbm_device));
ON_CALL(env->egl, eglGetDisplay(fake_gbm_device))
Expand Down
7 changes: 4 additions & 3 deletions tests/unit-tests/platforms/mesa/kms/test_display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,10 @@ TEST_F(MesaDisplayTest, create_display)
.Times(Exactly(1));

/* Create an EGL window surface backed by the gbm surface */
EXPECT_CALL(mock_egl, eglCreateWindowSurface(mock_egl.fake_egl_display,
mock_egl.fake_configs[0],
mock_gbm.fake_gbm.surface, _))
EXPECT_CALL(mock_egl, eglCreatePlatformWindowSurfaceEXT(
mock_egl.fake_egl_display,
mock_egl.fake_configs[0],
mock_gbm.fake_gbm.surface, _))
.Times(Exactly(1));

/* Swap the EGL window surface to bring the back buffer to the front */
Expand Down
6 changes: 3 additions & 3 deletions tests/unit-tests/platforms/mesa/kms/test_platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class MesaGraphicsPlatform : public ::testing::Test
Mock::VerifyAndClearExpectations(&mock_drm);
Mock::VerifyAndClearExpectations(&mock_gbm);
ON_CALL(mock_egl, eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS))
.WillByDefault(Return("EGL_AN_extension_string EGL_KHR_platform_gbm"));
.WillByDefault(Return("EGL_AN_extension_string EGL_EXT_platform_base EGL_KHR_platform_gbm"));
ON_CALL(mock_egl, eglGetDisplay(_))
.WillByDefault(Return(fake_display));
ON_CALL(mock_gl, glGetString(GL_RENDERER))
Expand Down Expand Up @@ -231,7 +231,7 @@ TEST_F(MesaGraphicsPlatform, probe_returns_supported_when_old_egl_mesa_gbm_platf
udev_environment.add_standard_device("standard-drm-devices");

ON_CALL(mock_egl, eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS))
.WillByDefault(Return("EGL_KHR_not_really_an_extension EGL_MESA_platform_gbm EGL_EXT_master_of_the_house"));
.WillByDefault(Return("EGL_KHR_not_really_an_extension EGL_MESA_platform_gbm EGL_EXT_master_of_the_house EGL_EXT_platform_base"));

mir::SharedLibrary platform_lib{mtf::server_platform("graphics-mesa-kms")};
auto probe = platform_lib.load_function<mg::PlatformProbe>(probe_platform);
Expand All @@ -250,7 +250,7 @@ TEST_F(MesaGraphicsPlatform, probe_returns_unsupported_when_gbm_platform_not_sup
udev_environment.add_standard_device("standard-drm-devices");

ON_CALL(mock_egl, eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS))
.WillByDefault(Return("EGL_KHR_not_really_an_extension EGL_EXT_master_of_the_house"));
.WillByDefault(Return("EGL_KHR_not_really_an_extension EGL_EXT_platform_base"));

mir::SharedLibrary platform_lib{mtf::server_platform("graphics-mesa-kms")};
auto probe = platform_lib.load_function<mg::PlatformProbe>(probe_platform);
Expand Down

0 comments on commit 8b44db3

Please sign in to comment.