Skip to content

Commit

Permalink
platforms/gbm-kms: Oops. Actually hook up DMABufEGLProvider.
Browse files Browse the repository at this point in the history
It turns out that just having a `shared_ptr<DMABufEGLProvider>` isn't enough, you need
to actually initialise it! Who knew!
  • Loading branch information
RAOF committed Sep 14, 2023
1 parent 54ce2d2 commit 3a226de
Show file tree
Hide file tree
Showing 7 changed files with 229 additions and 159 deletions.
2 changes: 2 additions & 0 deletions src/platforms/gbm-kms/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ add_library(
display_helpers.cpp
buffer_allocator.cpp
buffer_allocator.h
surfaceless_egl_context.h
surfaceless_egl_context.cpp
)

target_include_directories(
Expand Down
136 changes: 17 additions & 119 deletions src/platforms/gbm-kms/server/buffer_allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "display_helpers.h"
#include "mir/graphics/egl_error.h"
#include "cpu_copy_output_surface.h"
#include "surfaceless_egl_context.h"

#include <boost/throw_exception.hpp>
#include <boost/exception/errinfo_errno.hpp>
Expand Down Expand Up @@ -66,120 +67,14 @@ namespace mgg = mg::gbm;
namespace mgc = mg::common;
namespace geom = mir::geometry;

namespace
{
auto make_share_only_context(EGLDisplay dpy, std::optional<EGLContext> share_with) -> EGLContext
{
eglBindAPI(EGL_OPENGL_ES_API);

static const EGLint context_attr[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};

EGLint const config_attr[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};

EGLConfig cfg;
EGLint num_configs;

if (eglChooseConfig(dpy, config_attr, &cfg, 1, &num_configs) != EGL_TRUE || num_configs != 1)
{
BOOST_THROW_EXCEPTION((mg::egl_error("Failed to find any matching EGL config")));
}

auto ctx = eglCreateContext(dpy, cfg, share_with.value_or(EGL_NO_CONTEXT), context_attr);
if (ctx == EGL_NO_CONTEXT)
{
BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL context"));
}
return ctx;
}

class SurfacelessEGLContext : public mir::renderer::gl::Context
{
public:
SurfacelessEGLContext(EGLDisplay dpy)
: dpy{dpy},
ctx{make_share_only_context(dpy, {})}
{
}

SurfacelessEGLContext(EGLDisplay dpy, EGLContext share_with)
: dpy{dpy},
ctx{make_share_only_context(dpy, share_with)}
{
}

~SurfacelessEGLContext() override
{
eglDestroyContext(dpy, ctx);
}

void make_current() const override
{
if (eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx) != EGL_TRUE)
{
BOOST_THROW_EXCEPTION(mg::egl_error("Failed to make context current"));
}
}

void release_current() const override
{
if (eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) != EGL_TRUE)
{
BOOST_THROW_EXCEPTION(mg::egl_error("Failed to release current EGL context"));
}
}

auto make_share_context() const -> std::unique_ptr<Context> override
{
return std::unique_ptr<Context>{new SurfacelessEGLContext{dpy, ctx}};
}

explicit operator EGLContext() override
{
return ctx;
}
private:
EGLDisplay const dpy;
EGLContext const ctx;
};

auto maybe_make_dmabuf_provider(
EGLDisplay dpy,
std::shared_ptr<mg::EGLExtensions> egl_extensions,
std::shared_ptr<mgc::EGLContextExecutor> egl_delegate)
-> std::shared_ptr<mg::DMABufEGLProvider>
{
try
{
mg::EGLExtensions::EXTImageDmaBufImportModifiers modifier_ext{dpy};
return std::make_shared<mg::DMABufEGLProvider>(dpy, std::move(egl_extensions), modifier_ext, std::move(egl_delegate));
}
catch (std::runtime_error const& error)
{
mir::log_info(
"Cannot enable linux-dmabuf import support: %s", error.what());
mir::log(
mir::logging::Severity::debug,
MIR_LOG_COMPONENT,
std::current_exception(),
"Detailed error: ");
}
return nullptr;
}
}

mgg::BufferAllocator::BufferAllocator(EGLDisplay dpy, EGLContext share_with)
: ctx{std::make_unique<SurfacelessEGLContext>(dpy, share_with)},
egl_delegate{
std::make_shared<mgc::EGLContextExecutor>(ctx->make_share_context())},
mgg::BufferAllocator::BufferAllocator(
std::unique_ptr<mgg::SurfacelessEGLContext> context,
std::shared_ptr<mgc::EGLContextExecutor> egl_delegate,
std::shared_ptr<mg::DMABufEGLProvider> dmabuf_provider)
: ctx{std::move(context)},
egl_delegate{std::move(egl_delegate)},
egl_extensions(std::make_shared<mg::EGLExtensions>()),
dmabuf_provider{maybe_make_dmabuf_provider(dpy, egl_extensions, egl_delegate)}
dmabuf_provider{std::move(dmabuf_provider)}
{
}

Expand Down Expand Up @@ -350,7 +245,11 @@ auto mgg::GLRenderingProvider::as_texture(std::shared_ptr<Buffer> buffer) -> std
{
return dmabuf_texture;
}
return std::dynamic_pointer_cast<gl::Texture>(buffer);
else if (auto tex = std::dynamic_pointer_cast<gl::Texture>(buffer))
{
return tex;
}
BOOST_THROW_EXCEPTION((std::runtime_error{"Failed to import buffer as texture; rendering will be incomplete"}));
}

namespace
Expand Down Expand Up @@ -645,15 +544,14 @@ auto mgg::GLRenderingProvider::make_framebuffer_provider(std::shared_ptr<Display

mgg::GLRenderingProvider::GLRenderingProvider(
std::shared_ptr<mg::GBMDisplayProvider> associated_display,
std::shared_ptr<mgc::EGLContextExecutor> egl_delegate,
std::shared_ptr<mg::DMABufEGLProvider> dmabuf_provider,
EGLDisplay dpy,
EGLContext ctx)
: bound_display{std::move(associated_display)},
dpy{dpy},
ctx{ctx},
egl_delegate{
std::make_shared<common::EGLContextExecutor>(
std::make_unique<SurfacelessEGLContext>(
dpy,
make_share_only_context(dpy, ctx)))}
dmabuf_provider{std::move(dmabuf_provider)},
egl_delegate{std::move(egl_delegate)}
{
}
10 changes: 8 additions & 2 deletions src/platforms/gbm-kms/server/buffer_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,17 @@ namespace gbm
{

class GLRenderingProvider;
class SurfacelessEGLContext;

class BufferAllocator:
public graphics::GraphicBufferAllocator
{
public:
BufferAllocator(EGLDisplay dpy, EGLContext share_with);

BufferAllocator(
std::unique_ptr<SurfacelessEGLContext> ctx,
std::shared_ptr<common::EGLContextExecutor> egl_delegate,
std::shared_ptr<DMABufEGLProvider> dmabuf_provider);

std::shared_ptr<Buffer> alloc_software_buffer(geometry::Size size, MirPixelFormat) override;
std::vector<MirPixelFormat> supported_pixel_formats() override;

Expand Down Expand Up @@ -86,6 +90,8 @@ class GLRenderingProvider : public graphics::GLRenderingProvider
public:
GLRenderingProvider(
std::shared_ptr<GBMDisplayProvider> associated_display,
std::shared_ptr<common::EGLContextExecutor> egl_delegate,
std::shared_ptr<DMABufEGLProvider> dmabuf_provider,
EGLDisplay dpy,
EGLContext ctx);

Expand Down
76 changes: 40 additions & 36 deletions src/platforms/gbm-kms/server/kms/platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@
#include "display.h"
#include "mir/console_services.h"
#include "mir/emergency_cleanup_registry.h"
#include "mir/graphics/egl_context_executor.h"
#include "mir/graphics/platform.h"
#include "mir/renderer/gl/context.h"
#include "mir/udev/wrapper.h"
#include "kms_framebuffer.h"
#include "mir/graphics/egl_error.h"
#include "mir/graphics/egl_extensions.h"
#include "one_shot_device_observer.h"
#include "mir/graphics/linux_dmabuf.h"
#include "mir/graphics/egl_context_executor.h"
#include "surfaceless_egl_context.h"
#include <gbm.h>

#define MIR_LOG_COMPONENT "platform-graphics-gbm-kms"
Expand Down Expand Up @@ -174,37 +178,6 @@ auto dpy_for_gbm_device(gbm_device* device) -> EGLDisplay
return egl_display;
}

auto make_share_only_context(EGLDisplay dpy) -> EGLContext
{
eglBindAPI(EGL_OPENGL_ES_API);

static const EGLint context_attr[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};

EGLint const config_attr[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};

EGLConfig cfg;
EGLint num_configs;

if (eglChooseConfig(dpy, config_attr, &cfg, 1, &num_configs) != EGL_TRUE || num_configs != 1)
{
BOOST_THROW_EXCEPTION((mg::egl_error("Failed to find any matching EGL config")));
}

auto ctx = eglCreateContext(dpy, cfg, EGL_NO_CONTEXT, context_attr);
if (ctx == EGL_NO_CONTEXT)
{
BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL context"));
}
return ctx;
}

struct display_provider_or_nothing
{
auto operator()(std::shared_ptr<mg::GBMDisplayProvider> provider) { return provider; }
Expand All @@ -216,6 +189,30 @@ struct gbm_device_from_hw
auto operator()(std::shared_ptr<mg::GBMDisplayProvider> const& provider) { return provider->gbm_device(); }
auto operator()(std::shared_ptr<gbm_device> device) { return device; }
};

auto maybe_make_dmabuf_provider(
EGLDisplay dpy,
std::shared_ptr<mg::EGLExtensions> egl_extensions,
std::shared_ptr<mg::common::EGLContextExecutor> egl_delegate)
-> std::shared_ptr<mg::DMABufEGLProvider>
{
try
{
mg::EGLExtensions::EXTImageDmaBufImportModifiers modifier_ext{dpy};
return std::make_shared<mg::DMABufEGLProvider>(dpy, std::move(egl_extensions), modifier_ext, std::move(egl_delegate));
}
catch (std::runtime_error const& error)
{
mir::log_info(
"Cannot enable linux-dmabuf import support: %s", error.what());
mir::log(
mir::logging::Severity::debug,
MIR_LOG_COMPONENT,
std::current_exception(),
"Detailed error: ");
}
return nullptr;
}
}

mgg::RenderingPlatform::RenderingPlatform(
Expand All @@ -229,16 +226,21 @@ mgg::RenderingPlatform::RenderingPlatform(
std::variant<std::shared_ptr<mg::GBMDisplayProvider>, std::shared_ptr<gbm_device>> hw)
: device{std::visit(gbm_device_from_hw{}, hw)},
bound_display{std::visit(display_provider_or_nothing{}, hw)},
dpy{initialise_egl(dpy_for_gbm_device(device.get()), 1, 4)},
share_ctx{make_share_only_context(dpy)}
share_ctx{std::make_unique<SurfacelessEGLContext>(initialise_egl(dpy_for_gbm_device(device.get()), 1, 4))},
egl_delegate{std::make_shared<mg::common::EGLContextExecutor>(share_ctx->make_share_context())},
dmabuf_provider{maybe_make_dmabuf_provider(share_ctx->egl_display(), std::make_shared<mg::EGLExtensions>(), egl_delegate)}
{
}

mgg::RenderingPlatform::~RenderingPlatform() = default;

mir::UniqueModulePtr<mg::GraphicBufferAllocator> mgg::RenderingPlatform::create_buffer_allocator(
mg::Display const&)
{
return make_module_ptr<mgg::BufferAllocator>(dpy, share_ctx);
return make_module_ptr<mgg::BufferAllocator>(
std::make_unique<SurfacelessEGLContext>(share_ctx->egl_display(), static_cast<EGLContext>(*share_ctx)),
egl_delegate,
dmabuf_provider);
}

auto mgg::RenderingPlatform::maybe_create_interface(
Expand All @@ -248,8 +250,10 @@ auto mgg::RenderingPlatform::maybe_create_interface(
{
return std::make_shared<mgg::GLRenderingProvider>(
bound_display,
dpy,
share_ctx);
egl_delegate,
dmabuf_provider,
share_ctx->egl_display(),
static_cast<EGLContext>(*share_ctx));
}
return nullptr;
}
Expand Down
15 changes: 13 additions & 2 deletions src/platforms/gbm-kms/server/kms/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,18 @@ class ConsoleServices;

namespace graphics
{
class DMABufEGLProvider;

namespace common
{
class EGLContextExecutor;
}

namespace gbm
{

class Quirks;
class SurfacelessEGLContext;

class Platform : public graphics::DisplayPlatform
{
Expand Down Expand Up @@ -83,6 +91,8 @@ class RenderingPlatform : public graphics::RenderingPlatform
udev::Device const& device,
std::vector<std::shared_ptr<graphics::DisplayInterfaceProvider>> const& displays);

~RenderingPlatform() override;

auto create_buffer_allocator(
graphics::Display const&) -> UniqueModulePtr<graphics::GraphicBufferAllocator> override;

Expand All @@ -96,8 +106,9 @@ class RenderingPlatform : public graphics::RenderingPlatform

std::shared_ptr<gbm_device> const device; ///< gbm_device this platform is created on, always valid.
std::shared_ptr<GBMDisplayProvider> const bound_display; ///< Associated Display, if any (nullptr is valid)
EGLDisplay const dpy;
EGLContext const share_ctx;
std::unique_ptr<SurfacelessEGLContext> const share_ctx;
std::shared_ptr<common::EGLContextExecutor> const egl_delegate;
std::shared_ptr<DMABufEGLProvider> const dmabuf_provider;
};
}
}
Expand Down
Loading

0 comments on commit 3a226de

Please sign in to comment.