Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Atomic KMS: enable bypass #3595

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,20 @@ Description: Display server for Ubuntu - platform library for X11
Contains the shared libraries required for the Mir server to interact with
the X11 platform.

Package: mir-platform-graphics-atomic-kms22
Section: libs
Architecture: linux-any
Multi-Arch: same
Pre-Depends: ${misc:Pre-Depends}
Depends: ${misc:Depends},
${shlibs:Depends},
Description: Display server for Ubuntu - platform library for Atomic KMS
Mir is a display server running on linux systems, with a focus on efficiency,
robust operation and a well-defined driver model.
.
Contains the shared libraries required for the Mir server to interact with
the hardware platform using the Mesa drivers and Atomic KMS API.

Package: mir-platform-graphics-gbm-kms22
Section: libs
Architecture: linux-any
Expand Down Expand Up @@ -404,6 +418,7 @@ Architecture: linux-any
Multi-Arch: same
Pre-Depends: ${misc:Pre-Depends}
Depends: ${misc:Depends},
mir-platform-graphics-atomic-kms,
mir-platform-graphics-gbm-kms,
mir-platform-graphics-x,
mir-platform-graphics-wayland,
Expand Down
1 change: 1 addition & 0 deletions debian/mir-platform-graphics-atomic-kms22.install
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
usr/lib/*/mir/server-platform/graphics-atomic-kms.so.22
2 changes: 1 addition & 1 deletion debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export DEB_BUILD_MAINT_OPTIONS
$(info COMMON_CONFIGURE_OPTIONS: ${COMMON_CONFIGURE_OPTIONS})
$(info DEB_BUILD_MAINT_OPTIONS: ${DEB_BUILD_MAINT_OPTIONS})

AVAILABLE_PLATFORMS=gbm-kms\;x11\;wayland\;eglstream-kms
AVAILABLE_PLATFORMS=atomic-kms\;gbm-kms\;x11\;wayland\;eglstream-kms

override_dh_auto_configure:
ifneq ($(filter armhf,$(DEB_HOST_ARCH)),)
Expand Down
2 changes: 2 additions & 0 deletions include/platform/mir/graphics/dmabuf_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ class DMABufBuffer : public NativeBufferBase
virtual auto layout() const -> gl::Texture::Layout = 0;

virtual auto size() const -> geometry::Size = 0;

virtual void on_consumed() {};
};
}
}
Expand Down
4 changes: 2 additions & 2 deletions include/platform/mir/graphics/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ class GBMDisplayAllocator : public DisplayAllocator
virtual auto make_surface(DRMFormat format, std::span<uint64_t> modifiers) -> std::unique_ptr<GBMSurface> = 0;
};

class DmaBufBuffer;
class DMABufBuffer;

class DmaBufDisplayAllocator : public DisplayAllocator
{
Expand All @@ -396,7 +396,7 @@ class DmaBufDisplayAllocator : public DisplayAllocator
{
};

virtual auto framebuffer_for(std::shared_ptr<DmaBufBuffer> buffer)
virtual auto framebuffer_for(std::shared_ptr<DMABufBuffer> buffer)
-> std::unique_ptr<Framebuffer> = 0;
};

Expand Down
2 changes: 1 addition & 1 deletion snap/snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ parts:
cmake-parameters:
- -DCMAKE_INSTALL_PREFIX=/usr
- -DMIR_ENABLE_WLCS_TESTS=OFF
- -DMIR_PLATFORM='gbm-kms;eglstream-kms;x11;wayland'
- -DMIR_PLATFORM='atomic-kms;gbm-kms;eglstream-kms;x11;wayland'
build-packages:
- build-essential
- eglexternalplatform-dev
Expand Down
11 changes: 8 additions & 3 deletions src/platform/graphics/linux_dmabuf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,7 @@ class DmabufTexBuffer :
: dpy{dpy},
tex{dpy, extensions, dma_buf, descriptor, std::move(egl_delegate)},
provider_{std::move(provider)},
on_consumed{std::move(on_consumed)},
on_consumed_{std::move(on_consumed)},
on_release{std::move(on_release)},
size_{dma_buf.size()},
has_alpha{format_has_known_alpha(dma_buf.format()).value_or(true)}, // Has-alpha is the safe default for unknown formats
Expand Down Expand Up @@ -1017,6 +1017,12 @@ class DmabufTexBuffer :
return this;
}

void on_consumed() override
{
on_consumed_();
on_consumed_ = [](){};
}

auto as_texture() -> DMABufTex*
{
/* We only get asked for a texture when the Renderer is about to
Expand All @@ -1025,7 +1031,6 @@ class DmabufTexBuffer :
*/
std::lock_guard lock{consumed_mutex};
on_consumed();
on_consumed = [](){};

return &tex;
}
Expand Down Expand Up @@ -1061,7 +1066,7 @@ class DmabufTexBuffer :
std::shared_ptr<mg::DMABufEGLProvider> const provider_;

std::mutex consumed_mutex;
std::function<void()> on_consumed;
std::function<void()> on_consumed_;
std::function<void()> const on_release;

geom::Size const size_;
Expand Down
164 changes: 156 additions & 8 deletions src/platforms/atomic-kms/server/kms/display_buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,27 @@
#include "gbm_display_allocator.h"
#include "mir/fd.h"
#include "mir/graphics/display_report.h"
#include "mir/graphics/drm_formats.h"
#include "mir/graphics/platform.h"
#include "mir/graphics/transformation.h"
#include "bypass.h"
#include "mir/fatal.h"
#include "mir/log.h"
#include "display_helpers.h"
#include "egl_helper.h"
#include "mir/graphics/egl_error.h"
#include "mir/graphics/gl_config.h"
#include "mir/graphics/dmabuf_buffer.h"

#include <algorithm>
#include <boost/throw_exception.hpp>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <cstdint>
#include <drm_fourcc.h>

#include <drm_mode.h>
#include <gbm.h>
#include <memory>
#include <stdexcept>
#include <chrono>
#include <xf86drm.h>
#include <xf86drmMode.h>

namespace mg = mir::graphics;
namespace mga = mir::graphics::atomic;
Expand All @@ -56,7 +57,8 @@ mga::DisplaySink::DisplaySink(
std::vector<std::shared_ptr<KMSOutput>> const& outputs,
geom::Rectangle const& area,
glm::mat2 const& transformation)
: gbm{std::move(gbm)},
: DmaBufDisplayAllocator(gbm, drm_fd),
gbm{std::move(gbm)},
listener(listener),
outputs(outputs),
event_handler{std::move(event_handler)},
Expand Down Expand Up @@ -335,6 +337,144 @@ void mga::DisplaySink::set_next_image(std::unique_ptr<Framebuffer> content)
}
}

namespace {
auto const MAX_PLANES = 4zu;

auto get_import_buffers(std::shared_ptr<mg::DMABufBuffer> buffer)
-> std::tuple<std::array<int, 4>, std::array<int, 4>, std::array<int, 4>, std::array<uint64_t, 4>>
{
auto const plane_descriptors = buffer->planes();
assert(plane_descriptors.size() <= MAX_PLANES);

// std::array becuase we can't really return int[4]
std::array<int, 4> dmabuf_fds = {0};
std::array<int, 4> pitches = {0};
std::array<int, 4> offsets = {0};
std::array<uint64_t, 4> modifiers = {0};

for (std::size_t i = 0; i < std::min(MAX_PLANES, plane_descriptors.size()); i++)
{
dmabuf_fds[i] = plane_descriptors[i].dma_buf;
pitches[i] = plane_descriptors[i].stride;
offsets[i] = plane_descriptors[i].offset;
modifiers[i] = buffer->modifier().value_or(DRM_FORMAT_MOD_INVALID);
}

return std::make_tuple(dmabuf_fds, pitches, offsets, modifiers);
}

auto import_gbm_bo(
std::shared_ptr<struct gbm_device> gbm,
std::shared_ptr<mg::DMABufBuffer> buffer,
std::array<int, 4> dmabuf_fds,
std::array<int, 4> pitches,
std::array<int, 4> offsets) -> std::shared_ptr<struct gbm_bo>
{
auto const plane_descriptors = buffer->planes();

gbm_import_fd_modifier_data import_data = {
.width = buffer->size().width.as_uint32_t(),
.height = buffer->size().height.as_uint32_t(),
.format = buffer->format(),
.num_fds = static_cast<uint32_t>(std::min(plane_descriptors.size(), MAX_PLANES)),
.fds = {dmabuf_fds[0], dmabuf_fds[1], dmabuf_fds[2], dmabuf_fds[3]},
.strides = {pitches[0], pitches[1], pitches[2], pitches[3]},
.offsets = {offsets[0], offsets[1], offsets[2], offsets[3]},
.modifier = buffer->modifier().value_or(DRM_FORMAT_MOD_NONE),
};

auto* gbm_bo = gbm_bo_import(gbm.get(), GBM_BO_IMPORT_FD_MODIFIER, (void*)&import_data, GBM_BO_USE_SCANOUT);
return std::shared_ptr<struct gbm_bo>(gbm_bo, &gbm_bo_destroy);
}

auto drm_fb_id_from_dma_buffer(
mir::Fd drm_fd, std::shared_ptr<struct gbm_device> const gbm, std::shared_ptr<mg::DMABufBuffer> buffer)
-> std::shared_ptr<uint32_t>
{
auto [dmabuf_fds, pitches, offsets, modifiers] = get_import_buffers(buffer);
auto gbm_bo = import_gbm_bo(gbm, buffer, dmabuf_fds, pitches, offsets);
if (!gbm_bo)
{
mir::log_warning("Failed to import buffer");
return {};
}

auto const plane_descriptors = buffer->planes();
uint32_t gem_handles[MAX_PLANES] = {0};
for (std::size_t i = 0; i < std::min(MAX_PLANES, plane_descriptors.size()); i++)
gem_handles[i] = gbm_bo_get_handle_for_plane(gbm_bo.get(), i).u32;

// Note that we capture `gbm_bo` so that its lifetime matches that of the fb_id
auto fb_id = std::shared_ptr<uint32_t>{
new uint32_t{0},
[drm_fd, gbm_bo](uint32_t* fb_id)
{
if (*fb_id)
drmModeRmFB(drm_fd, *fb_id);

delete fb_id;
}};

auto [width, height] = buffer->size();
int ret = drmModeAddFB2WithModifiers(
drm_fd,
width.as_uint32_t(),
height.as_uint32_t(),
buffer->format(),
gem_handles,
reinterpret_cast<uint32_t*>(pitches.data()),
reinterpret_cast<uint32_t*>(offsets.data()),
modifiers.data(),
fb_id.get(),
DRM_MODE_FB_MODIFIERS);

if (ret)
{
mir::log_warning("drmModeAddFB2WithModifiers returned an error: %d", ret);
return {};
}

return fb_id;
}
}

auto mga::DmaBufDisplayAllocator::framebuffer_for(std::shared_ptr<DMABufBuffer> buffer) -> std::unique_ptr<Framebuffer>
{
auto fb_id = drm_fb_id_from_dma_buffer(drm_fd(), gbm, buffer);

if (!fb_id)
{
return {};
}

struct AtomicKmsFbHandle : public mg::FBHandle
{
AtomicKmsFbHandle(std::shared_ptr<uint32_t> fb_handle, geometry::Size size) :
kms_fb_id{fb_handle},
size_{size}
{
}

virtual auto size() const -> geometry::Size override
{
return size_;
}

virtual operator uint32_t() const override
{
return *kms_fb_id;
}

private:
std::shared_ptr<uint32_t> kms_fb_id;
geometry::Size size_;
};

buffer->on_consumed();

return std::make_unique<AtomicKmsFbHandle>(fb_id, buffer->size());
}

auto mga::DisplaySink::maybe_create_allocator(DisplayAllocator::Tag const& type_tag)
-> DisplayAllocator*
{
Expand All @@ -354,5 +494,13 @@ auto mga::DisplaySink::maybe_create_allocator(DisplayAllocator::Tag const& type_
}
return gbm_allocator.get();
}
if(dynamic_cast<DmaBufDisplayAllocator::Tag const*>(&type_tag))
{
if (!bypass_allocator)
{
bypass_allocator = std::make_shared<DmaBufDisplayAllocator>(gbm, drm_fd());
}
return bypass_allocator.get();
}
return nullptr;
}
29 changes: 27 additions & 2 deletions src/platforms/atomic-kms/server/kms/display_sink.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "platform_common.h"
#include "kms_framebuffer.h"

#include <boost/iostreams/detail/buffer.hpp>
#include <future>
#include <vector>
#include <memory>
Expand All @@ -50,8 +51,31 @@ namespace atomic
class Platform;
class KMSOutput;

class DisplaySink : public graphics::DisplaySink,
public graphics::DisplaySyncGroup
class DmaBufDisplayAllocator : public graphics::DmaBufDisplayAllocator
{
public:
DmaBufDisplayAllocator(std::shared_ptr<struct gbm_device> const gbm, mir::Fd drm_fd) :
drm_fd_{drm_fd},
gbm{gbm}
{
}

virtual auto framebuffer_for(std::shared_ptr<DMABufBuffer> buffer) -> std::unique_ptr<Framebuffer> override;

auto drm_fd() -> mir::Fd const
{
return drm_fd_;
}

private:
mir::Fd const drm_fd_;
std::shared_ptr<struct gbm_device> const gbm;
};

class DisplaySink :
public graphics::DisplaySink,
public graphics::DisplaySyncGroup,
public DmaBufDisplayAllocator
{
public:
DisplaySink(
Expand Down Expand Up @@ -103,6 +127,7 @@ class DisplaySink : public graphics::DisplaySink,

std::shared_ptr<kms::DRMEventHandler> const event_handler;

std::shared_ptr<DmaBufDisplayAllocator> bypass_allocator;
std::shared_ptr<CPUAddressableDisplayAllocator> kms_allocator;
std::unique_ptr<GBMDisplayAllocator> gbm_allocator;

Expand Down
Loading
Loading