Permalink
Browse files

Inital WaylandAllocator

  • Loading branch information...
1 parent cd26d84 commit 7806af725993cb8666bd23531924cda58685a998 @mariogrip mariogrip committed Nov 29, 2017
View
@@ -186,6 +186,7 @@ pkg_check_modules(MIRCORE REQUIRED mircore)
pkg_check_modules(MIRPLATFORM REQUIRED mirplatform)
pkg_check_modules(MIRGLRENDERER REQUIRED mir-renderer-gl-dev)
pkg_check_modules(MIRRENDERER REQUIRED mirrenderer)
+pkg_check_modules(WAYLAND_SERVER REQUIRED wayland-server)
include_directories(
${PROJECT_SOURCE_DIR}
View
@@ -36,7 +36,8 @@ Build-Depends: cmake,
libudev-dev,
libglib2.0-dev,
libumockdev-dev (>= 0.6),
- umockdev (>= 0.8.7)
+ umockdev (>= 0.8.7),
+ libwayland-dev
Standards-Version: 3.9.4
Homepage: https://launchpad.net/mir-android-platform
# If you aren't a member of ~mir-team but need to upload packaging changes,
@@ -6,6 +6,7 @@ include_directories(
${EGL_INCLUDE_DIRS}
${GLESv2_INCLUDE_DIRS}
${ANDROID_PROPERTIES_INCLUDE_DIRS}
+ ${WAYLAND_SERVER_INCLUDE_DIRS}
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
@@ -60,6 +61,7 @@ target_link_libraries(
${EGL_LDFLAGS} ${EGL_LIBRARIES}
${GLESv2_LDFLAGS} ${GLESv2_LIBRARIES}
${ANDROID_PROPERTIES_LDFLAGS}
+ ${WAYLAND_SERVER_LDFLAGS} ${WAYLAND_SERVER_LIBRARIES}
)
set_target_properties(
@@ -1,4 +1,5 @@
/*
+ * Copyright © 2017 The UBports project.
* Copyright © 2012 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
@@ -15,10 +16,12 @@
*
* Authored by:
* Kevin DuBois <kevin.dubois@canonical.com>
+ * Marius Gripsgard <marius@ubports.com>
*/
#include "mir/graphics/platform.h"
#include "mir/graphics/egl_extensions.h"
+#include "mir/graphics/egl_error.h"
#include "mir/graphics/buffer_properties.h"
#include "mir/graphics/buffer_ipc_message.h"
#include "cmdstream_sync_factory.h"
@@ -33,8 +36,13 @@
#include <boost/throw_exception.hpp>
+#include <wayland-server.h>
+
#include <stdexcept>
+#define MIR_LOG_COMPONENT "android-buffer-allocator"
+#include <mir/log.h>
+
namespace mg = mir::graphics;
namespace mga = mir::graphics::android;
namespace geom = mir::geometry;
@@ -88,7 +96,7 @@ std::shared_ptr<mg::Buffer> mga::GraphicBufferAllocator::alloc_buffer(
return std::make_shared<Buffer>(
reinterpret_cast<gralloc_module_t const*>(hw_module),
alloc_device->alloc_buffer(
- properties.size,
+ properties.size,
mga::to_android_format(properties.format),
mga::convert_to_android_usage(properties.usage)),
egl_extensions);
@@ -100,7 +108,7 @@ std::shared_ptr<mg::Buffer> mga::GraphicBufferAllocator::alloc_framebuffer(
return std::make_shared<Buffer>(
reinterpret_cast<gralloc_module_t const*>(hw_module),
alloc_device->alloc_buffer(
- size,
+ size,
mga::to_android_format(pf),
quirks->fb_gralloc_bits()),
egl_extensions);
@@ -138,3 +146,254 @@ std::shared_ptr<mg::Buffer> mga::GraphicBufferAllocator::alloc_buffer(
alloc_device->alloc_buffer(size, native_format, native_flags),
egl_extensions);
}
+
+namespace
+{
+class WaylandBuffer :
+ public mir::graphics::BufferBasic,
+ public mir::graphics::NativeBufferBase,
+ public mir::renderer::gl::TextureSource
+{
+public:
+ static std::shared_ptr<mg::Buffer> mir_buffer_from_wl_buffer(
+ EGLDisplay dpy,
+ wl_resource* buffer,
+ std::shared_ptr<mg::EGLExtensions> const& extensions,
+ std::function<void()>&& on_consumed)
+ {
+ std::shared_ptr<WaylandBuffer> mir_buffer;
+ DestructionShim* shim;
+
+ if (auto notifier = wl_resource_get_destroy_listener(buffer, &on_buffer_destroyed))
+ {
+ // We've already constructed a shim for this buffer, update it.
+ shim = wl_container_of(notifier, shim, destruction_listener);
+
+ if (!(mir_buffer = shim->associated_buffer.lock()))
+ {
+ /*
+ * We've seen this wl_buffer before, but all the WaylandBuffers associated with it
+ * have been destroyed.
+ *
+ * Recreate a new WaylandBuffer to track the new compositor lifetime.
+ */
+ mir_buffer = std::shared_ptr<WaylandBuffer>{
+ new WaylandBuffer{
+ dpy,
+ buffer,
+ extensions,
+ std::move(on_consumed)}};
+ shim->associated_buffer = mir_buffer;
+ }
+ }
+ else
+ {
+ mir_buffer = std::shared_ptr<WaylandBuffer>{
+ new WaylandBuffer{
+ dpy,
+ buffer,
+ extensions,
+ std::move(on_consumed)}};
+ shim = new DestructionShim;
+ shim->destruction_listener.notify = &on_buffer_destroyed;
+ shim->associated_buffer = mir_buffer;
+
+ wl_resource_add_destroy_listener(buffer, &shim->destruction_listener);
+ }
+
+ mir_buffer->buffer_mutex = shim->mutex;
+ return mir_buffer;
+ }
+
+ ~WaylandBuffer()
+ {
+ if (egl_image != EGL_NO_IMAGE_KHR)
+ extensions->eglDestroyImageKHR(dpy, egl_image);
+
+ std::lock_guard<std::mutex> lock{*buffer_mutex};
+ if (buffer)
+ {
+ wl_resource_queue_event(buffer, WL_BUFFER_RELEASE);
+ }
+ }
+
+ void gl_bind_to_texture() override
+ {
+ std::unique_lock<std::mutex> lock{*buffer_mutex};
+ if (buffer == nullptr)
+ {
+ mir::log_warning("WaylandBuffer::gl_bind_to_texture() called on a destroyed wl_buffer", this);
+ return;
+ }
+ if (egl_image == EGL_NO_IMAGE_KHR)
+ {
+ eglBindAPI(MIR_SERVER_EGL_OPENGL_API);
+
+ const EGLint image_attrs[] =
+ {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_NONE
+ };
+
+ egl_image = extensions->eglCreateImageKHR(
+ dpy,
+ EGL_NO_CONTEXT,
+ EGL_WAYLAND_BUFFER_WL,
+ buffer,
+ image_attrs);
+
+ if (egl_image == EGL_NO_IMAGE_KHR)
+ BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGLImage"));
+
+ on_consumed();
+ }
+ lock.unlock();
+
+ extensions->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image);
+ }
+
+ void bind() override
+ {
+ gl_bind_to_texture();
+ }
+
+ void secure_for_render() override
+ {
+ }
+
+ std::shared_ptr<mir::graphics::NativeBuffer> native_buffer_handle() const override
+ {
+ return nullptr;
+ }
+
+ mir::geometry::Size size() const override
+ {
+ return mir::geometry::Size{width, height};
+ }
+
+ MirPixelFormat pixel_format() const override
+ {
+ return format;
+ }
+
+ mir::graphics::NativeBufferBase *native_buffer_base() override
+ {
+ return this;
+ }
+
+private:
+ WaylandBuffer(
+ EGLDisplay dpy,
+ wl_resource* buffer,
+ std::shared_ptr<mg::EGLExtensions> const& extensions,
+ std::function<void()>&& on_consumed)
+ : buffer{buffer},
+ dpy{dpy},
+ egl_image{EGL_NO_IMAGE_KHR},
+ extensions{extensions},
+ on_consumed{std::move(on_consumed)}
+ {
+ if (extensions->wayland->eglQueryWaylandBufferWL(dpy, buffer, EGL_WIDTH, &width) == EGL_FALSE)
+ {
+ BOOST_THROW_EXCEPTION(mg::egl_error("Failed to query WaylandAllocator buffer width"));
+ }
+ if (extensions->wayland->eglQueryWaylandBufferWL(dpy, buffer, EGL_HEIGHT, &height) == EGL_FALSE)
+ {
+ BOOST_THROW_EXCEPTION(mg::egl_error("Failed to query WaylandAllocator buffer height"));
+ }
+
+ EGLint texture_format;
+ if (!extensions->wayland->eglQueryWaylandBufferWL(dpy, buffer, EGL_TEXTURE_FORMAT, &texture_format))
+ {
+ BOOST_THROW_EXCEPTION(mg::egl_error("Failed to query WL buffer format"));
+ }
+
+ if (texture_format == EGL_TEXTURE_RGB)
+ {
+ format = mir_pixel_format_xrgb_8888;
+ }
+ else if (texture_format == EGL_TEXTURE_RGBA)
+ {
+ format = mir_pixel_format_argb_8888;
+ }
+ else
+ {
+ BOOST_THROW_EXCEPTION((std::invalid_argument{"YUV buffers are unimplemented"}));
+ }
+ }
+
+ static void on_buffer_destroyed(wl_listener* listener, void*)
+ {
+ static_assert(
+ std::is_standard_layout<DestructionShim>::value,
+ "DestructionShim must be Standard Layout for wl_container_of to be defined behaviour");
+
+ DestructionShim* shim;
+ shim = wl_container_of(listener, shim, destruction_listener);
+
+ {
+ std::lock_guard<std::mutex> lock{*shim->mutex};
+ if (auto mir_buffer = shim->associated_buffer.lock())
+ {
+ mir_buffer->buffer = nullptr;
+ }
+ }
+
+ delete shim;
+ }
+
+ struct DestructionShim
+ {
+ std::shared_ptr<std::mutex> const mutex = std::make_shared<std::mutex>();
+ std::weak_ptr<WaylandBuffer> associated_buffer;
+ wl_listener destruction_listener;
+ };
+
+ std::shared_ptr<std::mutex> buffer_mutex;
+ wl_resource* buffer;
+
+ EGLDisplay dpy;
+ EGLImageKHR egl_image;
+
+ EGLint width, height;
+ MirPixelFormat format;
+
+ std::shared_ptr<mg::EGLExtensions> const extensions;
+
+ std::function<void()> on_consumed;
+};
+}
+
+void mga::GraphicBufferAllocator::bind_display(wl_display* display)
+{
+ dpy = eglGetCurrentDisplay();
+
+ if (dpy == EGL_NO_DISPLAY)
+ BOOST_THROW_EXCEPTION((std::logic_error{"WaylandAllocator::bind_display called without an active EGL Display"}));
+
+ if (!egl_extensions->wayland)
+ {
+ mir::log_warning("No EGL_WL_bind_wayland_display support");
+ return;
+ }
+
+ if (egl_extensions->wayland->eglBindWaylandDisplayWL(dpy, display) == EGL_FALSE)
+ {
+ BOOST_THROW_EXCEPTION(mg::egl_error("Failed to bind Wayland display"));
+ }
+ else
+ {
+ mir::log_info("Bound WaylandAllocator display");
+ }
+}
+
+std::shared_ptr<mg::Buffer> mga::GraphicBufferAllocator::buffer_from_resource (wl_resource* buffer, std::function<void ()>&& on_consumed)
+{
+ if (egl_extensions->wayland)
+ return WaylandBuffer::mir_buffer_from_wl_buffer(
+ dpy,
+ buffer,
+ egl_extensions,
+ std::move(on_consumed));
+ return nullptr;
+}
Oops, something went wrong.

0 comments on commit 7806af7

Please sign in to comment.