在研究DRM和libdrm的时候,不可避免地研究到了Kwin源码,因此专门开一个专栏详细记录一下研究过的KWin的相关知识点。
由于笔者一直做底层,使用的是C语言,对于C++只能说熟悉,算不上熟练,因此过程中难免有疏漏之处,望见谅同时欢迎指正。
作为本系列的第一篇文章,先来看一下src/backends/drm/overview.md,对于作为KWin后端的DRM进行了解和把握。
全部内容如下:
Documentation on the drm/kms API is sparse and split up in a few places and files, mostly in the Linux kernel code.
This file is meant to provide an overview for drm/kms and gbm to provide a starting point for understanding how the APIs and the drm backend work.
# drm/kms
In the drm API there is a few objects that we care about:
- `connector`s. A drm connector represents either an actual physical connector out of your graphics card or, in the case of DisplayPort MultiStream, a virtual one
- `crtc`s. A drm crtc represents hardware that can drive a connector uniquely - be it physical or virtual. Crtcs can also drive multiple connectors by cloning, aka showing the same stuff on all of them. The number of crtcs on your GPU or display device is a hard limit of how many display you can drive with it
- `plane`s. A drm plane represents scanout hardware that can be used for hardware composition, so cropping, scaling and rotation. There is multiple types of planes:
* `primary`: it can be asssumed that without the primary plane the output won't work. The kernel will always expose one per crtc
* `cursor`: cursor planes are what they sound like, they allow to use special hardware built for cursors. They have special restrictions like size (DRM_CAP_CURSOR_WIDTH, DRM_CAP_CURSOR_HEIGHT), scaling (on AMD gpus its scaling must be the same as with the primary scale) and even position on some very funky hardware (Apple stuff). Cursor planes are always optional
* `overlay`: overlay planes are what they sound like as well, they allow to use special hardware built for overlays (or underlays). The restrictions on this are of arbitrary complexity, you can never just assume they work. Overlay planes are also always optional
- `framebuffer`s, fb for short. These represent some sort of buffer that we'd like to show up on the screen and have to be created and destroyed by us
- `encoder`s. Can effectively be ignored, they were exposed in the API more or less by mistake and are just there for backwards compatibility
All drm objects have properties with a name and a value. Depending on the type this value can have a different meaning; some are a bitfield, some are just integer values and some are for arbitrary data blobs. Properties can be read-only (immutable) and are only informational, some are needed for functionality.
There's two APIs for drm, legacy and atomic modesetting (AMS).
Legacy only exposes connectors and crtcs, and only some of their properties. You first enable a connector and set a mode with `drmModeSetCrtc` and then push new frames with `drmModePageFlip`. `drmModePageFlip` has two flags we care about:
- `DRM_MODE_PAGE_FLIP_EVENT` tells the kernel to generate a page flip event for the crtc, which tells us when the new framebuffer has actually been set / when the old one is not needed anymore
- `DRM_MODE_PAGE_FLIP_ASYNC` tells the kernel that it should immediately apply the new framebuffer without waiting. This may cause tearing
For dynamic power management (dpms) you set the dpms property with `drmModeObjectSetProperty` and the kernel will handle the rest behind the scenes, or fail the request. Same story with `VRR_ENABLED`, `overscan` and similar.
With atomic modesetting all objects and properties are exposed. AMS works very differently from legacy: it has one generic function `drmModeAtomicCommit` that is used for pretty much everything. How this function works is that you first fill a `drmModeAtomicReq` with the properties you want to set, then you call `drmModeAtomicCommit` with some combination of flags. These flags decide on what the function actually does:
- `DRM_MODE_ATOMIC_TEST_ONLY` only tests whether or not the configuration would work but is guaranteed to not change anything
- `DRM_MODE_PAGE_FLIP_EVENT` tells the kernel that it should generate a page flip event for all crtcs that we change in the commit
- `DRM_MODE_ATOMIC_NONBLOCK` tells the kernel to make this function not blocking; it should not wait until things are actually applied before returning
- `DRM_MODE_ATOMIC_ALLOW_MODESET` tells the kernel that it is allowed to make our changes happen with a modeset, that is an event that can cause the display(s) to flicker or black out for a moment
- `DRM_MODE_PAGE_FLIP_ASYNC` is currently *not* supported. All requests with this flag set fail
Some upstream documentation can be found at https://www.kernel.org/doc/html/latest/gpu/drm-kms.html, https://01.org/linuxgraphics/gfx-docs/drm/drm-kms-properties.html and in the files at https://github.com/torvalds/linux/tree/master/drivers/gpu/drm.
For a lot of documentation on properties and capabilities of devices there's also https://drmdb.emersion.fr/
# gbm
The generic buffer manager API allows us to allocate buffers in graphics memory with a few properties. It's a relatively straight forward API:
- `gbm_bo` is a gbm buffer. It can be manually created and destroyed
- `gbm_surface` is a gbm surface, which allows us to create an egl surface that's using gbm buffers. With it we can render in egl and then create framebuffers from the things rendered in egl and present them on the display
- the `GBM_FORMAT_*` defines are just copies of the `DRM_FORMAT_*` defines in drm_fourcc.h and describe a buffer format. For example `DRM_FORMAT_XRGB8888` describes a buffer with 8 bits of red, 8 bits of green, 8 bits of blue and 8 bits of unused alpha (that's what the `X` stands for). Do not use the `GBM_BO_FORMAT_*` enum, it can cause problems! In general, ignore the buffer formats from the gbm header and instead use what drm_fourcc.h provides
- modifiers describe the actual memory layout that needs to be assumed for accessing the buffer. Older drivers like `radeon` don't support modifiers at all, on the other end of the spectrum the NVidia driver requires them. When we don't use functions that have us explicitly provide modifiers that's called an "implicit modifier" - that means the driver automatically picks a modifier for the use case. With implicit modifiers we have no guarantees about multi-gpu compatibility by default, instead the `GBM_BO_USE_LINEAR` usage flag has to be set when creating the buffer to enforce a linear format that all drivers can access without messing up the image
For gbm most of the upstream documentation is contained in https://gitlab.freedesktop.org/mesa/mesa/-/blob/main/src/gbm/main/gbm.c
第1段
Documentation on the drm/kms API is sparse and split up in a few places and files, mostly in the Linux kernel code.
关于drm/kms API的文档是稀疏的,并且被拆分为几个地方和文件,主要是在Linux内核代码中。
第2段
This file is meant to provide an overview for drm/kms and gbm to provide a starting point for understanding how the APIs and the drm backend work.
本文件旨在提供drm/kms和gbm的概述,为理解API和drm后端的工作方式提供一个起点。
第3段
# drm/kms
In the drm API there is a few objects that we care about:
drm/kms
在drm API中,有几个对象是我们关心的:
第4段
- `connector`s. A drm connector represents either an actual physical connector out of your graphics card or, in the case of DisplayPort MultiStream, a virtual one
一个drm connector代表连接(你的)显卡的一个实际物理连接器,或者代表一个虚拟连接器,在DisplayPort MultiStream的情况下。
第5段
- `crtc`s. A drm crtc represents hardware that can drive a connector uniquely - be it physical or virtual. Crtcs can also drive multiple connectors by cloning, aka showing the same stuff on all of them. The number of crtcs on your GPU or display device is a hard limit of how many display you can drive with it
一个drm crtc表示可以唯一驱动连接器的硬件——无论是物理连接器还是虚拟连接器。crtcs还可以通过克隆驱动多个连接器,也就是在所有连接器上显示相同的内容。GPU或显示设备上的crtcs的数量是一个硬性限制,限制了可以用它驱动多少显示器。
第6段
- `plane`s. A drm plane represents scanout hardware that can be used for hardware composition, so cropping, scaling and rotation. There is multiple types of planes:
* `primary`: it can be asssumed that without the primary plane the output won't work. The kernel will always expose one per crtc
* `cursor`: cursor planes are what they sound like, they allow to use special hardware built for cursors. They have special restrictions like size (DRM_CAP_CURSOR_WIDTH, DRM_CAP_CURSOR_HEIGHT), scaling (on AMD gpus its scaling must be the same as with the primary scale) and even position on some very funky hardware (Apple stuff). Cursor planes are always optional
* `overlay`: overlay planes are what they sound like as well, they allow to use special hardware built for overlays (or underlays). The restrictions on this are of arbitrary complexity, you can never just assume they work. Overlay planes are also always optional
一个drm plane表示可用于硬件合成的扫描输出硬件,如裁剪、缩放和旋转。有多种类型的plane:
第7段
- `framebuffer`s, fb for short. These represent some sort of buffer that we'd like to show up on the screen and have to be created and destroyed by us
简写为fb。其代表了我们想要在屏幕上显示的某种缓冲区,必须由我们创建和销毁。
第8段
- `encoder`s. Can effectively be ignored, they were exposed in the API more or less by mistake and are just there for backwards compatibility
可以被有效地忽略,它们或多或少地被错误地暴露在API中,只是为了向后兼容性。
第9段
All drm objects have properties with a name and a value. Depending on the type this value can have a different meaning; some are a bitfield, some are just integer values and some are for arbitrary data blobs. Properties can be read-only (immutable) and are only informational, some are needed for functionality.
所有drm对象都具有带有名称和值的属性。根据类型的不同,该值可能具有不同的含义:有些是位域;有些只是整数值;有些用于任意数据块。属性可以是只读的(不可变的),并且只是信息性的,有些是功能所必需的。
余下内容请参见下一篇文章。
第10段
There's two APIs for drm, legacy and atomic modesetting (AMS).
drm中有两个APIs,legacy(旧有)和atomic modesetting(AMS)。