From 9991dac4812e524a4316313b4910eddb7eb05254 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Thu, 21 Feb 2019 19:14:57 +0100 Subject: [PATCH] Make wpe_fdo_initialize_for_egl_display return bool Check that all required EGL extensions are available and that initialization doesn't fail. This is an API change but it's both API and ABI backwards compatible. --- include/wpe-fdo/initialize-egl.h | 3 +- src/initialize-egl.cpp | 4 +- src/view-backend-exportable-fdo-egl.cpp | 118 +----------------- src/ws.cpp | 154 +++++++++++++++++++++++- src/ws.h | 7 +- 5 files changed, 162 insertions(+), 124 deletions(-) diff --git a/include/wpe-fdo/initialize-egl.h b/include/wpe-fdo/initialize-egl.h index 1e06c5f..bbbd942 100644 --- a/include/wpe-fdo/initialize-egl.h +++ b/include/wpe-fdo/initialize-egl.h @@ -35,8 +35,9 @@ extern "C" { #endif #include +#include -void +bool wpe_fdo_initialize_for_egl_display(EGLDisplay); #ifdef __cplusplus diff --git a/src/initialize-egl.cpp b/src/initialize-egl.cpp index c75ade9..1d725b0 100644 --- a/src/initialize-egl.cpp +++ b/src/initialize-egl.cpp @@ -28,8 +28,8 @@ #include "ws.h" __attribute__((visibility("default"))) -void +bool wpe_fdo_initialize_for_egl_display(EGLDisplay display) { - WS::Instance::singleton().initialize(display); + return WS::Instance::singleton().initialize(display); } diff --git a/src/view-backend-exportable-fdo-egl.cpp b/src/view-backend-exportable-fdo-egl.cpp index 459d900..5e9df6a 100644 --- a/src/view-backend-exportable-fdo-egl.cpp +++ b/src/view-backend-exportable-fdo-egl.cpp @@ -34,33 +34,6 @@ namespace { -#ifndef EGL_EXT_image_dma_buf_import -#define EGL_LINUX_DMA_BUF_EXT 0x3270 -#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272 -#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273 -#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274 -#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275 -#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276 -#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277 -#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278 -#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279 -#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A -#endif /* EGL_EXT_image_dma_buf_import */ - -#ifndef EGL_EXT_image_dma_buf_import_modifiers -#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440 -#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441 -#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442 -#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443 -#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444 -#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445 -#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446 -#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447 -#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448 -#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449 -#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A -#endif /* EGL_EXT_image_dma_buf_import_modifiers */ - struct buffer_data { struct wl_resource *buffer_resource; EGLImageKHR egl_image; @@ -73,22 +46,13 @@ class ClientBundleEGL final : public ClientBundle { : ClientBundle(data, viewBackend, initialWidth, initialHeight) , client(_client) { - m_eglDisplay = WS::Instance::singleton().getEGLDisplay(); - assert (m_eglDisplay); - - eglCreateImage = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress ("eglCreateImageKHR"); - assert (eglCreateImage); - - eglDestroyImage = (PFNEGLDESTROYIMAGEKHRPROC) - eglGetProcAddress ("eglDestroyImageKHR"); - assert (eglDestroyImage); } virtual ~ClientBundleEGL() { for (auto* buf_data : m_buffers) { assert(buf_data->egl_image); - eglDestroyImage(m_eglDisplay, buf_data->egl_image); + WS::Instance::singleton().destroyImage(buf_data->egl_image); delete buf_data; } @@ -97,15 +61,7 @@ class ClientBundleEGL final : public ClientBundle { void exportBuffer(struct wl_resource *bufferResource) override { - static const EGLint image_attrs[] = { - EGL_WAYLAND_PLANE_WL, 0, - EGL_NONE - }; - EGLImageKHR image = eglCreateImage (m_eglDisplay, - EGL_NO_CONTEXT, - EGL_WAYLAND_BUFFER_WL, - bufferResource, - image_attrs); + EGLImageKHR image = WS::Instance::singleton().createImage(bufferResource); if (!image) return; @@ -119,69 +75,7 @@ class ClientBundleEGL final : public ClientBundle { void exportBuffer(const struct linux_dmabuf_buffer *dmabuf_buffer) override { - const struct linux_dmabuf_attributes *buf_attribs = - linux_dmabuf_get_buffer_attributes(dmabuf_buffer); - assert(buf_attribs); - - static const struct { - EGLint fd; - EGLint offset; - EGLint pitch; - EGLint modifier_lo; - EGLint modifier_hi; - } plane_enums[4] = { - {EGL_DMA_BUF_PLANE0_FD_EXT, - EGL_DMA_BUF_PLANE0_OFFSET_EXT, - EGL_DMA_BUF_PLANE0_PITCH_EXT, - EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, - EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT}, - {EGL_DMA_BUF_PLANE1_FD_EXT, - EGL_DMA_BUF_PLANE1_OFFSET_EXT, - EGL_DMA_BUF_PLANE1_PITCH_EXT, - EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, - EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT}, - {EGL_DMA_BUF_PLANE2_FD_EXT, - EGL_DMA_BUF_PLANE2_OFFSET_EXT, - EGL_DMA_BUF_PLANE2_PITCH_EXT, - EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, - EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT}, - {EGL_DMA_BUF_PLANE3_FD_EXT, - EGL_DMA_BUF_PLANE3_OFFSET_EXT, - EGL_DMA_BUF_PLANE3_PITCH_EXT, - EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, - EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT}, - }; - - EGLint attribs[50]; - int atti = 0; - - attribs[atti++] = EGL_WIDTH; - attribs[atti++] = buf_attribs->width; - attribs[atti++] = EGL_HEIGHT; - attribs[atti++] = buf_attribs->height; - attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; - attribs[atti++] = buf_attribs->format; - - for (int i = 0; i < buf_attribs->n_planes; i++) { - attribs[atti++] = plane_enums[i].fd; - attribs[atti++] = buf_attribs->fd[i]; - attribs[atti++] = plane_enums[i].offset; - attribs[atti++] = buf_attribs->offset[i]; - attribs[atti++] = plane_enums[i].pitch; - attribs[atti++] = buf_attribs->stride[i]; - attribs[atti++] = plane_enums[i].modifier_lo; - attribs[atti++] = buf_attribs->modifier[i] & 0xFFFFFFFF; - attribs[atti++] = plane_enums[i].modifier_hi; - attribs[atti++] = buf_attribs->modifier[i] >> 32; - } - - attribs[atti++] = EGL_NONE; - - EGLImageKHR image = eglCreateImage (m_eglDisplay, - EGL_NO_CONTEXT, - EGL_LINUX_DMA_BUF_EXT, - nullptr, - attribs); + EGLImageKHR image = WS::Instance::singleton().createImage(dmabuf_buffer); if (!image) return; @@ -198,7 +92,7 @@ class ClientBundleEGL final : public ClientBundle { for (auto* buf_data : m_buffers) if (buf_data->egl_image == image) { m_buffers.remove(buf_data); - eglDestroyImage(m_eglDisplay, buf_data->egl_image); + WS::Instance::singleton().destroyImage(buf_data->egl_image); return buf_data; } @@ -209,10 +103,6 @@ class ClientBundleEGL final : public ClientBundle { const struct wpe_view_backend_exportable_fdo_egl_client* client; private: - EGLDisplay m_eglDisplay; - PFNEGLCREATEIMAGEKHRPROC eglCreateImage; - PFNEGLDESTROYIMAGEKHRPROC eglDestroyImage; - std::list m_buffers; }; diff --git a/src/ws.cpp b/src/ws.cpp index 7acda4c..917937b 100644 --- a/src/ws.cpp +++ b/src/ws.cpp @@ -29,6 +29,7 @@ #include #include "linux-dmabuf/linux-dmabuf.h" #include "bridge/wpe-bridge-server-protocol.h" +#include #include #include @@ -36,6 +37,37 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display); #endif +#ifndef EGL_EXT_image_dma_buf_import +#define EGL_LINUX_DMA_BUF_EXT 0x3270 +#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272 +#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273 +#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274 +#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275 +#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276 +#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277 +#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278 +#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279 +#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A +#endif /* EGL_EXT_image_dma_buf_import */ + +#ifndef EGL_EXT_image_dma_buf_import_modifiers +#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440 +#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441 +#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442 +#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443 +#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444 +#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445 +#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446 +#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447 +#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448 +#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449 +#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A +#endif /* EGL_EXT_image_dma_buf_import_modifiers */ + +static PFNEGLBINDWAYLANDDISPLAYWL eglBindWaylandDisplayWL; +static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; +static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; + namespace WS { struct Source { @@ -258,28 +290,60 @@ Instance::~Instance() wl_display_destroy(m_display); } -void Instance::initialize(EGLDisplay eglDisplay) +static bool isEGLExtensionSupported(const char* extensionList, const char* extension) +{ + if (!extensionList) + return false; + + int extensionLen = strlen(extension); + const char* extensionListPtr = extensionList; + while ((extensionListPtr = strstr(extensionListPtr, extension))) { + if (extensionListPtr[extensionLen] == ' ' || extensionListPtr[extensionLen] == '\0') + return true; + extensionListPtr += extensionLen; + } + return false; +} + +bool Instance::initialize(EGLDisplay eglDisplay) { if (m_eglDisplay == eglDisplay) - return; + return true; if (m_eglDisplay != EGL_NO_DISPLAY) { fprintf(stderr, "WPE fdo doesn't support multiple EGL displays\n"); - return; + return false; } - PFNEGLBINDWAYLANDDISPLAYWL bindWaylandDisplayWL = - reinterpret_cast(eglGetProcAddress("eglBindWaylandDisplayWL")); - bindWaylandDisplayWL(eglDisplay, m_display); + const char* extensions = eglQueryString(eglDisplay, EGL_EXTENSIONS); + if (isEGLExtensionSupported(extensions, "EGL_WL_bind_wayland_display")) + eglBindWaylandDisplayWL = reinterpret_cast(eglGetProcAddress("eglBindWaylandDisplayWL")); + if (!eglBindWaylandDisplayWL) + return false; + + if (isEGLExtensionSupported(extensions, "EGL_KHR_image_base")) { + eglCreateImageKHR = reinterpret_cast(eglGetProcAddress("eglCreateImageKHR")); + eglDestroyImageKHR = reinterpret_cast(eglGetProcAddress("eglDestroyImageKHR")); + } + if (!eglCreateImageKHR || !eglDestroyImageKHR) + return false; + + if (!eglBindWaylandDisplayWL(eglDisplay, m_display)) + return false; m_eglDisplay = eglDisplay; /* Initialize Linux dmabuf subsystem. */ linux_dmabuf_setup(m_display, eglDisplay); + + return true; } int Instance::createClient() { + if (m_eglDisplay == EGL_NO_DISPLAY) + return -1; + int pair[2]; if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, pair) < 0) return -1; @@ -296,6 +360,84 @@ void Instance::createSurface(uint32_t id, Surface* surface) m_viewBackendMap.insert({ id, surface }); } +EGLImageKHR Instance::createImage(struct wl_resource* resourceBuffer) +{ + if (m_eglDisplay == EGL_NO_DISPLAY) + return EGL_NO_IMAGE_KHR; + return eglCreateImageKHR(m_eglDisplay, EGL_NO_CONTEXT, EGL_WAYLAND_BUFFER_WL, resourceBuffer, nullptr); +} + +EGLImageKHR Instance::createImage(const struct linux_dmabuf_buffer* dmabufBuffer) +{ + if (m_eglDisplay == EGL_NO_DISPLAY) + return EGL_NO_IMAGE_KHR; + const struct linux_dmabuf_attributes* bufAttribs = + linux_dmabuf_get_buffer_attributes(dmabufBuffer); + assert(bufAttribs); + + static const struct { + EGLint fd; + EGLint offset; + EGLint pitch; + EGLint modifierLo; + EGLint modifierHi; + } planeEnums[4] = { + {EGL_DMA_BUF_PLANE0_FD_EXT, + EGL_DMA_BUF_PLANE0_OFFSET_EXT, + EGL_DMA_BUF_PLANE0_PITCH_EXT, + EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, + EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT}, + {EGL_DMA_BUF_PLANE1_FD_EXT, + EGL_DMA_BUF_PLANE1_OFFSET_EXT, + EGL_DMA_BUF_PLANE1_PITCH_EXT, + EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, + EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT}, + {EGL_DMA_BUF_PLANE2_FD_EXT, + EGL_DMA_BUF_PLANE2_OFFSET_EXT, + EGL_DMA_BUF_PLANE2_PITCH_EXT, + EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, + EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT}, + {EGL_DMA_BUF_PLANE3_FD_EXT, + EGL_DMA_BUF_PLANE3_OFFSET_EXT, + EGL_DMA_BUF_PLANE3_PITCH_EXT, + EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, + EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT}, + }; + + EGLint attribs[50]; + int atti = 0; + attribs[atti++] = EGL_WIDTH; + attribs[atti++] = bufAttribs->width; + attribs[atti++] = EGL_HEIGHT; + attribs[atti++] = bufAttribs->height; + attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; + attribs[atti++] = bufAttribs->format; + + for (int i = 0; i < bufAttribs->n_planes; i++) { + attribs[atti++] = planeEnums[i].fd; + attribs[atti++] = bufAttribs->fd[i]; + attribs[atti++] = planeEnums[i].offset; + attribs[atti++] = bufAttribs->offset[i]; + attribs[atti++] = planeEnums[i].pitch; + attribs[atti++] = bufAttribs->stride[i]; + attribs[atti++] = planeEnums[i].modifierLo; + attribs[atti++] = bufAttribs->modifier[i] & 0xFFFFFFFF; + attribs[atti++] = planeEnums[i].modifierHi; + attribs[atti++] = bufAttribs->modifier[i] >> 32; + } + + attribs[atti++] = EGL_NONE; + + return eglCreateImageKHR(m_eglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, attribs); +} + +void Instance::destroyImage(EGLImageKHR image) +{ + if (m_eglDisplay == EGL_NO_DISPLAY) + return; + eglDestroyImageKHR(m_eglDisplay, image); +} + struct wl_client* Instance::registerViewBackend(uint32_t id, ExportableClient& exportableClient) { auto it = m_viewBackendMap.find(id); diff --git a/src/ws.h b/src/ws.h index c858048..36b0259 100644 --- a/src/ws.h +++ b/src/ws.h @@ -31,6 +31,7 @@ #include "linux-dmabuf/linux-dmabuf.h" typedef void *EGLDisplay; +typedef void *EGLImageKHR; namespace WS { @@ -47,7 +48,7 @@ class Instance { static Instance& singleton(); ~Instance(); - void initialize(EGLDisplay); + bool initialize(EGLDisplay); int createClient(); @@ -60,6 +61,10 @@ class Instance { return m_eglDisplay; } + EGLImageKHR createImage(struct wl_resource*); + EGLImageKHR createImage(const struct linux_dmabuf_buffer*); + void destroyImage(EGLImageKHR); + private: Instance();