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

Initial Atomic KMS platform #3525

Merged
merged 27 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ec4e20f
platforms/common: Add mgk::get_cap_checked()
RAOF Aug 5, 2024
ba3b2f3
platforms/common: Add missing `mgk::ObjectProperties` implementations
RAOF Aug 5, 2024
59dd726
platforms: Add atomic-kms platform
RAOF Aug 5, 2024
e9a505f
platforms/atomic-kms: Populate supported pixel formats correctly (#3596)
RAOF Oct 1, 2024
0dc388b
Fix DRM FB using CRTC width/height
tarek-y-ismail Oct 9, 2024
7a6c934
platforms/atomic-kms: Fix `AtomicKMSOutput::clear_crtc`
RAOF Oct 17, 2024
b5f03e0
platforms/atomic-kms: Fix `AtomicKMSOutput::set_power_mode`
RAOF Oct 17, 2024
6b5ec1d
platforms/atomic-kms: Fix modesetting with `AtomicKMSOutput::set_crtc`
RAOF Oct 17, 2024
3c2d3ca
platforms/atomic-kms: Fix log message.
RAOF Oct 17, 2024
99e65ba
platforms/atomic-kms: Don't try to pageflip incorrectly sized FBs
RAOF Oct 17, 2024
b09ddee
platforms/atomic-kms: Make DisplaySink associated with exactly one KM…
RAOF Oct 18, 2024
ebac9f3
Drop dead code
AlanGriffiths Oct 23, 2024
4e3489b
Consistent and non-conflicting header guards
AlanGriffiths Oct 23, 2024
b847994
Naked #include <gbm.h>
AlanGriffiths Oct 23, 2024
2f539f9
Rationalise DMIR_LOG_COMPONENT
AlanGriffiths Oct 23, 2024
484154f
Use std::tie to compare structs by member
AlanGriffiths Oct 23, 2024
e9e94f9
Inline pointless variable
AlanGriffiths Oct 23, 2024
3ffc1e2
Clearer memory management
AlanGriffiths Oct 23, 2024
72c7038
Insert egl version major and minor into exception
AlanGriffiths Oct 23, 2024
8082102
debian: package atomic-kms (#3607)
Saviq Oct 23, 2024
1b0062f
Failing to get gamma curves shouldn't be fatal in `AtomicKMSOutput::u…
AlanGriffiths Oct 24, 2024
a816adb
platforms/atomic-kms: Don't crash on pageflip failure.
RAOF Oct 24, 2024
75910a6
platforms/atomic-kms: Synchronise access to CRTC configuration.
RAOF Oct 25, 2024
ee57db3
platforms/atomic-kms: Clean up unused resources in `refresh_hardware_…
RAOF Oct 30, 2024
bec4b25
platforms/atomic-kms: Always set CRTC to ACTIVE when doing a modeset
RAOF Nov 7, 2024
3aae8bb
platforms/atomic-kms: Log when DPMS setting fails
RAOF Nov 7, 2024
5efbaef
platforms/atomic-kms: Release resources for disconnected outputs.
RAOF Nov 7, 2024
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
13 changes: 8 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -161,18 +161,18 @@ pkg_check_modules(WAYLAND_EGLSTREAM wayland-eglstream IMPORTED_TARGET)
if (WAYLAND_EGLSTREAM_FOUND)
set(
MIR_PLATFORM
gbm-kms;x11;eglstream-kms;wayland
gbm-kms;atomic-kms;x11;eglstream-kms;wayland
CACHE
STRING
"a list of graphics backends to build (options are 'gbm-kms', 'x11', 'eglstream-kms', or 'wayland')"
"a list of graphics backends to build (options are 'gbm-kms', 'atomic-kms', 'x11', 'eglstream-kms', or 'wayland')"
)
else()
set(
MIR_PLATFORM
gbm-kms;x11;wayland
gbm-kms;atomic-kms;x11;wayland
CACHE
STRING
"a list of graphics backends to build (options are 'gbm-kms', 'x11', 'eglstream-kms', or 'wayland')"
"a list of graphics backends to build (options are 'gbm-kms', 'atomic-kms', 'x11', 'eglstream-kms', or 'wayland')"
)
endif()

Expand Down Expand Up @@ -209,6 +209,9 @@ foreach(platform IN LISTS MIR_PLATFORM)
if (platform STREQUAL "gbm-kms")
set(MIR_BUILD_PLATFORM_GBM_KMS TRUE)
endif()
if (platform STREQUAL "atomic-kms")
set(MIR_BUILD_PLATFORM_ATOMIC_KMS TRUE)
endif()
if (platform STREQUAL "x11")
set(MIR_BUILD_PLATFORM_X11 TRUE)
endif()
Expand Down Expand Up @@ -263,7 +266,7 @@ if (HAVE_SYS_SDT_H)
add_compile_definitions(LTTNG_UST_HAVE_SDT_INTEGRATION)
endif()

if (MIR_BUILD_PLATFORM_GBM_KMS)
if (MIR_BUILD_PLATFORM_GBM_KMS OR MIR_BUILD_PLATFORM_ATOMIC_KMS)
pkg_check_modules(GBM REQUIRED IMPORTED_TARGET gbm>=11.0.0)
endif()

Expand Down
32 changes: 32 additions & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,21 @@ 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: mir-platform-graphics-gbm-kms22,
${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 +419,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 All @@ -416,6 +432,22 @@ Description: Display server for Ubuntu - desktop driver metapackage
This package depends on a full set of graphics and input drivers for traditional desktop
systems.

Package: mir-platform-graphics-atomic-kms
Section: libs
Architecture: linux-any
Multi-Arch: same
Pre-Depends: ${misc:Pre-Depends}
Depends: ${misc:Depends},
mir-platform-graphics-atomic-kms22,
mir-platform-input-evdev10,
mir-platform-rendering-egl-generic,
Description: Display server for Ubuntu - gbm-kms driver metapackage
Mir is a display server running on linux systems, with a focus on efficiency,
robust operation and a well-defined driver model.
.
This package depends on a full set of graphics and input drivers for atomic-kms
systems.

Package: mir-platform-graphics-gbm-kms
Section: libs
Architecture: linux-any
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: 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
4 changes: 4 additions & 0 deletions src/platforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ if (MIR_BUILD_PLATFORM_GBM_KMS)
add_subdirectory(gbm-kms/)
endif()

if (MIR_BUILD_PLATFORM_ATOMIC_KMS)
add_subdirectory(atomic-kms/)
endif()

if (MIR_BUILD_PLATFORM_X11)
add_subdirectory(x11/)
endif()
Expand Down
2 changes: 2 additions & 0 deletions src/platforms/atomic-kms/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
add_definitions(-DMIR_LOG_COMPONENT_FALLBACK="atomic-kms")
add_subdirectory(server/)
24 changes: 24 additions & 0 deletions src/platforms/atomic-kms/server/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
add_subdirectory(kms/)

add_library(
mirsharedatomickmscommon-static STATIC

display_helpers.cpp
gbm_display_allocator.h
gbm_display_allocator.cpp
)

target_include_directories(
mirsharedatomickmscommon-static
PUBLIC
${server_common_include_dirs}
${CMAKE_CURRENT_BINARY_DIR}
)

target_link_libraries(
mirsharedatomickmscommon-static

server_platform_common
kms_utils
mirplatform
)
240 changes: 240 additions & 0 deletions src/platforms/atomic-kms/server/display_helpers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
/*
* 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 "display_helpers.h"
#include "one_shot_device_observer.h"

#include "kms-utils/drm_mode_resources.h"
#include "mir/graphics/egl_error.h"
#include "kms/quirks.h"

#include "mir/udev/wrapper.h"
#include "mir/console_services.h"

#include <sys/sysmacros.h>

#include "mir/log.h"

#include <boost/exception/errinfo_errno.hpp>
#include <boost/throw_exception.hpp>

#include <cstring>
#include <stdexcept>
#include <xf86drm.h>
#include <fcntl.h>
#include <vector>
#include <boost/exception/diagnostic_information.hpp>

namespace mg = mir::graphics;
namespace mga = mir::graphics::atomic;
namespace mgc = mir::graphics::common;
namespace mgmh = mir::graphics::atomic::helpers;

/*************
* DRMHelper *
*************/

std::vector<std::shared_ptr<mgmh::DRMHelper>>
mgmh::DRMHelper::open_all_devices(
std::shared_ptr<mir::udev::Context> const& udev,
mir::ConsoleServices& console,
mga::Quirks const& quirks)
{
int error = ENODEV; //Default error is "there are no DRM devices"

mir::udev::Enumerator devices(udev);
devices.match_subsystem("drm");
devices.match_sysname("card[0-9]");

devices.scan_devices();

std::vector<std::shared_ptr<DRMHelper>> opened_devices;

for(auto& device : devices)
{
if (quirks.should_skip(device))
{
mir::log_info("Ignoring device %s due to specified quirk", device.devnode());
continue;
}

mir::Fd tmp_fd;
std::unique_ptr<mir::Device> device_handle;
try
{
device_handle = console.acquire_device(
major(device.devnum()), minor(device.devnum()),
std::make_unique<mgc::OneShotDeviceObserver>(tmp_fd))
.get();
}
catch (std::exception const& error)
{
mir::log_warning(
"Failed to open DRM device node %s: %s",
device.devnode(),
boost::diagnostic_information(error).c_str());
continue;
}

// Paranoia is always justified when dealing with hardware interfaces…
if (tmp_fd == mir::Fd::invalid)
{
mir::log_critical(
"Opening the DRM device %s succeeded, but provided an invalid descriptor!",
device.devnode());
mir::log_critical(
"This is probably a logic error in Mir, please report to https://github.com/MirServer/mir/issues");
continue;
}

// Check that the drm device is usable by setting the interface version we use (1.4)
drmSetVersion sv;
sv.drm_di_major = 1;
sv.drm_di_minor = 4;
sv.drm_dd_major = -1; /* Don't care */
sv.drm_dd_minor = -1; /* Don't care */

if ((error = -drmSetInterfaceVersion(tmp_fd, &sv)))
{
mir::log_warning(
"Failed to set DRM interface version on device %s: %i (%s)",
device.devnode(),
error,
strerror(error));
continue;
}

auto busid = std::unique_ptr<char, decltype(&drmFreeBusid)>{
drmGetBusid(tmp_fd), &drmFreeBusid
};

if (!busid)
{
mir::log_warning(
"Failed to query BusID for device %s; cannot check if KMS is available",
device.devnode());
}
else
{
switch (auto err = -drmCheckModesettingSupported(busid.get()))
{
case 0: break;

case ENOSYS:
if (quirks.require_modesetting_support(device))
{
mir::log_info("Ignoring non-KMS DRM device %s", device.devnode());
error = ENOSYS;
continue;
}

[[fallthrough]];
case EINVAL:
mir::log_warning(
"Failed to detect whether device %s supports KMS, but continuing anyway",
device.devnode());
break;

default:
mir::log_warning("Unexpected error from drmCheckModesettingSupported(): %s (%i), but continuing anyway",
strerror(err), err);
mir::log_warning("Please file a bug at https://github.com/MirServer/mir/issues containing this message");
}
}

// Can't use make_shared with the private constructor.
opened_devices.push_back(
std::shared_ptr<DRMHelper>{
new DRMHelper{
std::move(tmp_fd),
std::move(device_handle)}});
mir::log_info("Using DRM device %s", device.devnode());
}

if (opened_devices.size() == 0)
{
BOOST_THROW_EXCEPTION((
std::system_error{error, std::system_category(), "Error opening DRM device"}));
}

return opened_devices;
}

std::unique_ptr<mgmh::DRMHelper> mgmh::DRMHelper::open_any_render_node(
std::shared_ptr<mir::udev::Context> const& udev)
{
mir::Fd tmp_fd;
int error = ENODEV; //Default error is "there are no DRM devices"

mir::udev::Enumerator devices(udev);
devices.match_subsystem("drm");
devices.match_sysname("renderD[0-9]*");

devices.scan_devices();

for(auto& device : devices)
{
// If directly opening the DRM device is good enough for X it's good enough for us!
tmp_fd = mir::Fd{open(device.devnode(), O_RDWR | O_CLOEXEC)};
if (tmp_fd < 0)
{
error = errno;
continue;
}

break;
}

if (tmp_fd < 0)
{
BOOST_THROW_EXCEPTION((
std::system_error{
error,
std::system_category(),
"Error opening DRM device"}));
}

return std::unique_ptr<mgmh::DRMHelper>{
new mgmh::DRMHelper{std::move(tmp_fd), nullptr}};
}

mgmh::DRMHelper::DRMHelper(mir::Fd&& fd, std::unique_ptr<mir::Device> device)
: fd{std::move(fd)},
device_handle{std::move(device)}
{
}

mgmh::DRMHelper::~DRMHelper()
{
}

/*************
* GBMHelper *
*************/

mgmh::GBMHelper::GBMHelper(mir::Fd const& drm_fd)
: device{gbm_create_device(drm_fd)}
{
if (!device)
BOOST_THROW_EXCEPTION(
std::runtime_error("Failed to create GBM device"));
}

mgmh::GBMHelper::~GBMHelper()
{
if (device)
gbm_device_destroy(device);
}
Loading
Loading