| <?xml version='1.0'?> <!--*-nxml-*--> |
| <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" |
| "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> |
| |
| <!-- |
| Written 2012 by David Herrmann <dh.herrmann@googlemail.com> |
| Dedicated to the Public Domain |
| --> |
| |
| <refentry id="drm-kms"> |
| <refentryinfo> |
| <title>Direct Rendering Manager</title> |
| <productname>libdrm</productname> |
| <date>September 2012</date> |
| <authorgroup> |
| <author> |
| <contrib>Developer</contrib> |
| <firstname>David</firstname> |
| <surname>Herrmann</surname> |
| <email>dh.herrmann@googlemail.com</email> |
| </author> |
| </authorgroup> |
| </refentryinfo> |
| |
| <refmeta> |
| <refentrytitle>drm-kms</refentrytitle> |
| <manvolnum>7</manvolnum> |
| </refmeta> |
| |
| <refnamediv> |
| <refname>drm-kms</refname> |
| <refpurpose>Kernel Mode-Setting</refpurpose> |
| </refnamediv> |
| |
| <refsynopsisdiv> |
| <funcsynopsis> |
| <funcsynopsisinfo>#include <xf86drm.h></funcsynopsisinfo> |
| <funcsynopsisinfo>#include <xf86drmMode.h></funcsynopsisinfo> |
| </funcsynopsis> |
| </refsynopsisdiv> |
| |
| <refsect1> |
| <title>Description</title> |
| <para>Each DRM device provides access to manage which monitors and displays |
| are currently used and what frames to be displayed. This task is |
| called <emphasis>Kernel Mode-Setting</emphasis> (KMS). Historically, |
| this was done in user-space and called |
| <emphasis>User-space Mode-Setting</emphasis> (UMS). Almost all |
| open-source drivers now provide the KMS kernel API to do this in the |
| kernel, however, many non-open-source binary drivers from different |
| vendors still do not support this. You can use |
| <citerefentry><refentrytitle>drmModeSettingSupported</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| to check whether your driver supports this. To understand how KMS |
| works, we need to introduce 5 objects: <emphasis>CRTCs</emphasis>, |
| <emphasis>Planes</emphasis>, <emphasis>Encoders</emphasis>, |
| <emphasis>Connectors</emphasis> and |
| <emphasis>Framebuffers</emphasis>. |
| |
| <variablelist> |
| <varlistentry> |
| <term>CRTCs</term> |
| <listitem> |
| <para>A <emphasis>CRTC</emphasis> short for |
| <emphasis>CRT Controller</emphasis> is an abstraction |
| representing a part of the chip that contains a pointer to a |
| scanout buffer. Therefore, the number of CRTCs available |
| determines how many independent scanout buffers can be active |
| at any given time. The CRTC structure contains several fields |
| to support this: a pointer to some video memory (abstracted as |
| a frame-buffer object), a list of driven connectors, a display |
| mode and an (x, y) offset into the video memory to support |
| panning or configurations where one piece of video memory |
| spans multiple CRTCs. A CRTC is the central point where |
| configuration of displays happens. You select which objects to |
| use, which modes and which parameters and then configure each |
| CRTC via |
| <citerefentry><refentrytitle>drmModeCrtcSet</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| to drive the display devices.</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term>Planes</term> |
| <listitem> |
| <para>A <emphasis>plane</emphasis> respresents an image source that |
| can be blended with or overlayed on top of a CRTC during the |
| scanout process. Planes are associated with a frame-buffer to |
| crop a portion of the image memory (source) and optionally |
| scale it to a destination size. The result is then blended |
| with or overlayed on top of a CRTC. Planes are not provided by |
| all hardware and the number of available planes is limited. If |
| planes are not available or if not enough planes are |
| available, the user should fall back to normal software |
| blending (via GPU or CPU).</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term>Encoders</term> |
| <listitem> |
| <para>An <emphasis>encoder</emphasis> takes pixel data from a CRTC |
| and converts it to a format suitable for any attached |
| connectors. On some devices, it may be possible to have a CRTC |
| send data to more than one encoder. In that case, both |
| encoders would receive data from the same scanout buffer, |
| resulting in a <emphasis>cloned</emphasis> display |
| configuration across the connectors attached to each |
| encoder.</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term>Connectors</term> |
| <listitem> |
| <para>A <emphasis>connector</emphasis> is the final destination of |
| pixel-data on a device, and usually connects directly to an |
| external display device like a monitor or laptop panel. A |
| connector can only be attached to one encoder at a time. The |
| connector is also the structure where information about the |
| attached display is kept, so it contains fields for display |
| data, <emphasis>EDID</emphasis> data, |
| <emphasis>DPMS</emphasis> and |
| <emphasis>connection status</emphasis>, and information about |
| modes supported on the attached displays.</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term>Framebuffers</term> |
| <listitem> |
| <para><emphasis>Framebuffers</emphasis> are abstract memory objects |
| that provide a source of pixel data to scanout to a CRTC. |
| Applications explicitly request the creation of framebuffers |
| and can control their behavior. Framebuffers rely on the |
| underneath memory manager for low-level memory operations. |
| When creating a framebuffer, applications pass a memory handle |
| through the API which is used as backing storage. The |
| framebuffer itself is only an abstract object with no data. It |
| just refers to memory buffers that must be created with the |
| <citerefentry><refentrytitle>drm-memory</refentrytitle><manvolnum>7</manvolnum></citerefentry> |
| API.</para> |
| </listitem> |
| </varlistentry> |
| </variablelist> |
| </para> |
| |
| <refsect2> |
| <title>Mode-Setting</title> |
| <para>Before mode-setting can be performed, an application needs to call |
| <citerefentry><refentrytitle>drmSetMaster</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| to become <emphasis>DRM-Master</emphasis>. It then has exclusive |
| access to the KMS API. A call to |
| <citerefentry><refentrytitle>drmModeGetResources</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| returns a list of <emphasis>CRTCs</emphasis>, |
| <emphasis>Connectors</emphasis>, <emphasis>Encoders</emphasis> and |
| <emphasis>Planes</emphasis>.</para> |
| |
| <para>Normal procedure now includes: First, you select which connectors |
| you want to use. Users are mostly interested in which monitor or |
| display-panel is active so you need to make sure to arrange them in |
| the correct logical order and select the correct ones to use. For |
| each connector, you need to find a CRTC to drive this connector. If |
| you want to clone output to two or more connectors, you may use a |
| single CRTC for all cloned connectors (if the hardware supports |
| this). To find a suitable CRTC, you need to iterate over the list of |
| encoders that are available for each connector. Each encoder |
| contains a list of CRTCs that it can work with and you simply select |
| one of these CRTCs. If you later program the CRTC to control a |
| connector, it automatically selects the best encoder. However, this |
| procedure is needed so your CRTC has at least one working encoder |
| for the selected connector. See the <emphasis>Examples</emphasis> |
| section below for more information.</para> |
| |
| <para>All valid modes for a connector can be retrieved with a call to |
| <citerefentry><refentrytitle>drmModeGetConnector</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| You need to select the mode you want to use and save it. The first |
| mode in the list is the default mode with the highest resolution |
| possible and often a suitable choice.</para> |
| |
| <para>After you have a working connector+CRTC+mode combination, you need |
| to create a framebuffer that is used for scanout. Memory buffer |
| allocation is driver-depedent and described in |
| <citerefentry><refentrytitle>drm-memory</refentrytitle><manvolnum>7</manvolnum></citerefentry>. |
| You need to create a buffer big enough for your selected mode. Now |
| you can create a framebuffer object that uses your memory-buffer as |
| scanout buffer. You can do this with |
| <citerefentry><refentrytitle>drmModeAddFB</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| and |
| <citerefentry><refentrytitle>drmModeAddFB2</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> |
| |
| <para>As a last step, you want to program your CRTC to drive your selected |
| connector. You can do this with a call to |
| <citerefentry><refentrytitle>drmModeSetCrtc</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> |
| </refsect2> |
| |
| <refsect2> |
| <title>Page-Flipping</title> |
| <para>A call to |
| <citerefentry><refentrytitle>drmModeSetCrtc</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| is executed immediately and forces the CRTC to use the new scanout |
| buffer. If you want smooth-transitions without tearing, you probably |
| use double-buffering. You need to create one framebuffer object for |
| each buffer you use. You can then call |
| <citerefentry><refentrytitle>drmModeSetCrtc</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| on the next buffer to flip. If you want to synchronize your flips |
| with <emphasis>vertical-blanks</emphasis>, you can use |
| <citerefentry><refentrytitle>drmModePageFlip</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| which schedules your page-flip for the next |
| <emphasis>vblank</emphasis>.</para> |
| </refsect2> |
| |
| <refsect2> |
| <title>Planes</title> |
| <para>Planes are controlled independently from CRTCs. That is, a call to |
| <citerefentry><refentrytitle>drmModeSetCrtc</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| does not affect planes. Instead, you need to call |
| <citerefentry><refentrytitle>drmModeSetPlane</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| to configure a plane. This requires the plane ID, a CRTC, a |
| framebuffer and offsets into the plane-framebuffer and the |
| CRTC-framebuffer. The CRTC then blends the content from the plane |
| over the CRTC framebuffer buffer during scanout. As this does not |
| involve any software-blending, it is way faster than traditional |
| blending. However, plane resources are limited. See |
| <citerefentry><refentrytitle>drmModeGetPlaneResources</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| for more information.</para> |
| </refsect2> |
| |
| <refsect2> |
| <title>Cursors</title> |
| <para>Similar to planes, many hardware also supports cursors. A cursor is |
| a very small buffer with an image that is blended over the CRTC |
| framebuffer. You can set a different cursor for each CRTC with |
| <citerefentry><refentrytitle>drmModeSetCursor</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| and move it on the screen with |
| <citerefentry><refentrytitle>drmModeMoveCursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>. |
| This allows to move the cursor on the screen without rerendering. If |
| no hardware cursors are supported, you need to rerender for each |
| frame the cursor is moved.</para> |
| </refsect2> |
| |
| </refsect1> |
| |
| <refsect1> |
| <title>Examples</title> |
| <para>Some examples of how basic mode-setting can be done. See the man-page |
| of each DRM function for more information.</para> |
| |
| <refsect2> |
| <title>CRTC/Encoder Selection</title> |
| <para>If you retrieved all display configuration information via |
| <citerefentry><refentrytitle>drmModeGetResources</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| as <structname>drmModeRes</structname> *<varname>res</varname>, |
| selected a connector from the list in |
| <varname>res</varname>-><structfield>connectors</structfield> |
| and retrieved the connector-information as |
| <structname>drmModeConnector</structname> *<varname>conn</varname> |
| via |
| <citerefentry><refentrytitle>drmModeGetConnector</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| then this example shows, how you can find a suitable CRTC id to |
| drive this connector. This function takes a file-descriptor to the |
| DRM device (see |
| <citerefentry><refentrytitle>drmOpen</refentrytitle><manvolnum>3</manvolnum></citerefentry>) |
| as <varname>fd</varname>, a pointer to the retrieved resources as |
| <varname>res</varname> and a pointer to the selected connector as |
| <varname>conn</varname>. It returns an integer smaller than 0 on |
| failure, otherwise, a valid CRTC id is returned.</para> |
| |
| <programlisting> |
| static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn) |
| { |
| drmModeEncoder *enc; |
| unsigned int i, j; |
| |
| /* iterate all encoders of this connector */ |
| for (i = 0; i < conn->count_encoders; ++i) { |
| enc = drmModeGetEncoder(fd, conn->encoders[i]); |
| if (!enc) { |
| /* cannot retrieve encoder, ignoring... */ |
| continue; |
| } |
| |
| /* iterate all global CRTCs */ |
| for (j = 0; j < res->count_crtcs; ++j) { |
| /* check whether this CRTC works with the encoder */ |
| if (!(enc->possible_crtcs & (1 << j))) |
| continue; |
| |
| |
| /* Here you need to check that no other connector |
| * currently uses the CRTC with id "crtc". If you intend |
| * to drive one connector only, then you can skip this |
| * step. Otherwise, simply scan your list of configured |
| * connectors and CRTCs whether this CRTC is already |
| * used. If it is, then simply continue the search here. */ |
| if (res->crtcs[j] "is unused") { |
| drmModeFreeEncoder(enc); |
| return res->crtcs[j]; |
| } |
| } |
| |
| drmModeFreeEncoder(enc); |
| } |
| |
| /* cannot find a suitable CRTC */ |
| return -ENOENT; |
| } |
| </programlisting> |
| |
| </refsect2> |
| |
| </refsect1> |
| |
| <refsect1> |
| <title>Reporting Bugs</title> |
| <para>Bugs in this manual should be reported to |
| https://bugs.freedesktop.org/enter_bug.cgi?product=DRI&component=libdrm |
| under the "DRI" product, component "libdrm"</para> |
| </refsect1> |
| |
| <refsect1> |
| <title>See Also</title> |
| <para> |
| <citerefentry><refentrytitle>drm</refentrytitle><manvolnum>7</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drm-memory</refentrytitle><manvolnum>7</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModeGetResources</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModeGetConnector</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModeGetEncoder</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModeGetCrtc</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModeSetCrtc</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModeGetFB</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModeAddFB</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModeAddFB2</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModeRmFB</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModePageFlip</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModeGetPlaneResources</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModeGetPlane</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModeSetPlane</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModeSetCursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmModeMoveCursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmSetMaster</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmAvailable</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmCheckModesettingSupported</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| <citerefentry><refentrytitle>drmOpen</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| </para> |
| </refsect1> |
| </refentry> |