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

DRM: Explicit synchorisation support #3717

Open
wants to merge 6 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
51 changes: 51 additions & 0 deletions include/common/mir/time/posix_clock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@

#ifndef MIR_COMMON_TIME_POSIX_CLOCK_
#define MIR_COMMON_TIME_POSIX_CLOCK_

#include <chrono>

namespace mir::time
{
template<clockid_t clock_id>
struct is_steady_specialisation
{
static constexpr bool is_steady = false;
};

template<>
struct is_steady_specialisation<CLOCK_MONOTONIC>
{
static constexpr bool is_steady = true;
};

template<>
struct is_steady_specialisation<CLOCK_MONOTONIC_RAW>
{
static constexpr bool is_steady = true;
};

template<>
struct is_steady_specialisation<CLOCK_MONOTONIC_COARSE>
{
static constexpr bool is_steady = true;
};

auto clock_gettime_checked(clockid_t clock_id) -> std::chrono::nanoseconds;

template<clockid_t clock_id>
class PosixClock : public is_steady_specialisation<clock_id>
{
public:
typedef std::chrono::nanoseconds duration;
typedef duration::rep rep;
typedef duration::period period;
typedef std::chrono::time_point<PosixClock, duration> time_point;

static auto now() -> time_point
{
return time_point{clock_gettime_checked(clock_id)};
}
};
}

#endif // MIR_COMMON_TIME_POSIX_CLOCK_
39 changes: 39 additions & 0 deletions include/platform/mir/graphics/drm_syncobj.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright © Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 2 or 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "mir/fd.h"
#include "mir/time/posix_clock.h"

namespace mir::graphics::drm
{

class Syncobj
{
public:
Syncobj(Fd drm_fd, uint32_t handle);

~Syncobj();

auto wait(uint64_t point, time::PosixClock<CLOCK_MONOTONIC>::time_point until) const -> bool;

void signal(uint64_t point);

auto to_eventfd(uint64_t point) const -> Fd;
private:
Fd const drm_fd;
uint32_t const handle;
};
}
16 changes: 16 additions & 0 deletions include/platform/mir/graphics/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "mir/module_properties.h"
#include "mir/module_deleter.h"
#include "mir/renderer/sw/pixel_source.h"
#include "mir/fd.h"

#include <EGL/egl.h>

Expand Down Expand Up @@ -167,6 +168,21 @@ class GLRenderingProvider : public RenderingProvider
GLConfig const& config) -> std::unique_ptr<gl::OutputSurface> = 0;
};

namespace drm
{
class Syncobj;
}

class DRMRenderingProvider : public GLRenderingProvider
{
public:
class Tag : public RenderingProvider::Tag
{
};

virtual auto import_syncobj(mir::Fd const& syncobj_fd) -> std::unique_ptr<drm::Syncobj> = 0;
};

/**
* \defgroup platform_enablement Mir platform enablement
*
Expand Down
3 changes: 3 additions & 0 deletions src/common/symbols.map
Original file line number Diff line number Diff line change
Expand Up @@ -701,13 +701,16 @@ global:
MIR_COMMON_2.19 {
global:
extern "C++" {
mir::time::clock_gettime_checked*;
mir::time::is_steady_specialisation::is_steady*;
mir::SharedLibrary::Handle::?Handle*;
mir::SharedLibrary::Handle::operator*;
mir::SharedLibrary::get_handle*;
mir::SharedLibrary::Handle::HandleHash::operator*;
std::hash?mir::SharedLibrary::Handle?::operator*;
typeinfo?for?mir::SharedLibrary::Handle;
typeinfo?for?mir::SharedLibrary::Handle::HandleHash;
typeinfo?for?mir::time::is_steady_specialisation;
};
} MIR_COMMON_2.18;

2 changes: 2 additions & 0 deletions src/common/time/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ ADD_LIBRARY(
mirtime OBJECT

steady_clock.cpp
${PROJECT_SOURCE_DIR}/include/common/mir/time/posix_clock.h
posix_clock.cpp
)
33 changes: 33 additions & 0 deletions src/common/time/posix_clock.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "mir/time/posix_clock.h"
#include <chrono>
#include <ctime>
#include <system_error>
#include <boost/throw_exception.hpp>

namespace mt = mir::time;

auto mt::clock_gettime_checked(clockid_t clock_id) -> std::chrono::nanoseconds
{
struct timespec ts;
if (auto err = clock_gettime(clock_id, &ts))
{
BOOST_THROW_EXCEPTION((
std::system_error{
err,
std::system_category(),
"clock_gettime failed"}));
}
return std::chrono::nanoseconds{ts.tv_nsec + ts.tv_sec * std::chrono::nanoseconds::period::den};
}

static_assert(
std::chrono::is_clock_v<mt::PosixClock<CLOCK_MONOTONIC>>,
"PosixClock<CLOCK_MONOTONIC> is a Clock type");

static_assert(
mt::PosixClock<CLOCK_MONOTONIC>::is_steady,
"PosixClock<CLOCK_MONOTONIC> should be steady");

static_assert(
!mt::PosixClock<CLOCK_REALTIME>::is_steady,
"PosixClock<CLOCK_REALTIME> should not be steady");
2 changes: 2 additions & 0 deletions src/platform/graphics/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ add_library(mirplatformgraphicscommon OBJECT
egl_context_executor.cpp
egl_buffer_copy.h
egl_buffer_copy.cpp
${PROJECT_SOURCE_DIR}/include/platform/mir/graphics/drm_syncobj.h
drm_syncobj.cpp
)

mir_generate_protocol_wrapper(mirplatformgraphicscommon "zwp_" linux-dmabuf-unstable-v1.xml)
Expand Down
89 changes: 89 additions & 0 deletions src/platform/graphics/drm_syncobj.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include "mir/graphics/drm_syncobj.h"

#include "mir/log.h"

#include <boost/throw_exception.hpp>
#include <drm.h>
#include <sys/eventfd.h>
#include <system_error>
#include <xf86drm.h>

namespace mg = mir::graphics;
namespace mt = mir::time;

mg::drm::Syncobj::Syncobj(Fd drm_fd, uint32_t handle)
: drm_fd{std::move(drm_fd)},
handle{handle}
{
}

mg::drm::Syncobj::~Syncobj()
{
drmSyncobjDestroy(drm_fd, handle);
}

auto mg::drm::Syncobj::wait(uint64_t point, mt::PosixClock<CLOCK_MONOTONIC>::time_point until) const -> bool
{
if (auto err = drmSyncobjTimelineWait(
drm_fd,
const_cast<uint32_t *>(&handle),
&point,
1,
duration_cast<std::chrono::nanoseconds>(until.time_since_epoch()).count(),
DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, nullptr))
{
if (err == -ETIME)
{
// Timeout; this is not an error
return false;
}
BOOST_THROW_EXCEPTION((
std::system_error{
-err,
std::system_category(),
"Failed to wait for DRM sync timeline"
}
));
}
return true;
}

void mg::drm::Syncobj::signal(uint64_t point)
{
if (auto err = drmSyncobjTimelineSignal(
drm_fd,
&handle,
&point,
1))
{
BOOST_THROW_EXCEPTION((
std::system_error{
-err,
std::system_category(),
"Failed to signal DRM timeline syncpoint"
}
));
}
}

auto mg::drm::Syncobj::to_eventfd(uint64_t point) const -> Fd
{
mir::Fd event_fd{eventfd(0, EFD_CLOEXEC)};
if (event_fd == mir::Fd::invalid)
{
BOOST_THROW_EXCEPTION((
std::system_error{
errno,
std::system_category(),
"Failed to create eventfd"}));
}
if (auto err = drmSyncobjEventfd(drm_fd, handle, point, event_fd, 0))
{
BOOST_THROW_EXCEPTION((
std::system_error{
-err,
std::system_category(),
"Failed to associate eventfd with DRM sync point"}));
}
return event_fd;
}
24 changes: 24 additions & 0 deletions src/platform/graphics/drm_syncobj.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright © Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 2 or 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

namespace mir::graphics::drm
{
class Syncobj
{
public:
virtual ~Syncobj() = default;
};
}
5 changes: 5 additions & 0 deletions src/platform/symbols.map
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ MIR_PLATFORM_2.19 {
mir::graphics::wayland::bind_display*;
mir::graphics::wayland::buffer_from_resource*;
mir::graphics::wayland::unbind_display*;
mir::graphics::drm::Syncobj::Syncobj*;
mir::graphics::drm::Syncobj::?Syncobj*;
mir::graphics::drm::Syncobj::signal*;
mir::graphics::drm::Syncobj::to_eventfd*;
mir::graphics::drm::Syncobj::wait*;
mir::options::Configuration::?Configuration*;
mir::options::Configuration::Configuration*;
mir::options::Configuration::operator*;
Expand Down
20 changes: 19 additions & 1 deletion src/platforms/gbm-kms/server/buffer_allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "mir/graphics/egl_error.h"
#include "cpu_copy_output_surface.h"
#include "surfaceless_egl_context.h"
#include "mir/graphics/drm_syncobj.h"

#include <boost/throw_exception.hpp>
#include <boost/exception/errinfo_errno.hpp>
Expand Down Expand Up @@ -552,6 +553,21 @@ auto mgg::GLRenderingProvider::surface_for_sink(
config);
}

auto mgg::GLRenderingProvider::import_syncobj(Fd const& syncobj_fd)
-> std::unique_ptr<drm::Syncobj>
{
uint32_t handle;
if (auto err = drmSyncobjFDToHandle(drm_fd, syncobj_fd, &handle))
{
BOOST_THROW_EXCEPTION((
std::system_error{
-err,
std::system_category(),
"Failed to import DRM syncobj"}));
}
return std::make_unique<drm::Syncobj>(drm_fd, handle);
}

auto mgg::GLRenderingProvider::make_framebuffer_provider(DisplaySink& /*sink*/)
-> std::unique_ptr<FramebufferProvider>
{
Expand All @@ -570,12 +586,14 @@ auto mgg::GLRenderingProvider::make_framebuffer_provider(DisplaySink& /*sink*/)
}

mgg::GLRenderingProvider::GLRenderingProvider(
Fd drm_fd,
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)},
: drm_fd{std::move(drm_fd)},
bound_display{std::move(associated_display)},
dpy{dpy},
ctx{ctx},
dmabuf_provider{std::move(dmabuf_provider)},
Expand Down
6 changes: 5 additions & 1 deletion src/platforms/gbm-kms/server/buffer_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,11 @@ class BufferAllocator:
bool egl_display_bound{false};
};

class GLRenderingProvider : public graphics::GLRenderingProvider
class GLRenderingProvider : public graphics::DRMRenderingProvider
{
public:
GLRenderingProvider(
Fd drm_fd,
std::shared_ptr<GBMDisplayProvider> associated_display,
std::shared_ptr<common::EGLContextExecutor> egl_delegate,
std::shared_ptr<DMABufEGLProvider> dmabuf_provider,
Expand All @@ -109,7 +110,10 @@ class GLRenderingProvider : public graphics::GLRenderingProvider
DisplaySink& sink,
GLConfig const& config) -> std::unique_ptr<gl::OutputSurface> override;

auto import_syncobj(Fd const& syncobj_fd) -> std::unique_ptr<drm::Syncobj> override;

private:
Fd const drm_fd;
std::shared_ptr<GBMDisplayProvider> const bound_display; ///< Associated Display provider (if any - null is valid)
EGLDisplay const dpy;
EGLContext const ctx;
Expand Down
Loading
Loading