Drivers must initialize the mode setting core by calling
drm_mode_config_init
on the DRM device. The function
initializes the drm_device
mode_config
field and never fails. Once done,
mode configuration must be setup by initializing the following fields.
int min_width, min_height; int max_width, max_height;
Minimum and maximum width and height of the frame buffers in pixel units.
struct drm_mode_config_funcs *funcs;
Mode setting functions.
dmode
using vm
,
vm
using dmode
,
struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd);
Frame buffers are abstract memory objects that provide a source of pixels to scanout to a CRTC. Applications explicitly request the creation of frame buffers through the DRM_IOCTL_MODE_ADDFB(2) ioctls and receive an opaque handle that can be passed to the KMS CRTC control, plane configuration and page flip functions.
Frame buffers rely on the underneath memory manager for low-level memory
operations. When creating a frame buffer applications pass a memory
handle (or a list of memory handles for multi-planar formats) through
the drm_mode_fb_cmd2
argument. For drivers using
GEM as their userspace buffer management interface this would be a GEM
handle. Drivers are however free to use their own backing storage object
handles, e.g. vmwgfx directly exposes special TTM handles to userspace
and so expects TTM handles in the create ioctl and not GEM handles.
Drivers must first validate the requested frame buffer parameters passed through the mode_cmd argument. In particular this is where invalid sizes, pixel formats or pitches can be caught.
If the parameters are deemed valid, drivers then create, initialize and
return an instance of struct drm_framebuffer.
If desired the instance can be embedded in a larger driver-specific
structure. Drivers must fill its width
,
height
, pitches
,
offsets
, depth
,
bits_per_pixel
and
pixel_format
fields from the values passed
through the drm_mode_fb_cmd2
argument. They
should call the drm_helper_mode_fill_fb_struct
helper function to do so.
The initialization of the new framebuffer instance is finalized with a
call to drm_framebuffer_init
which takes a pointer
to DRM frame buffer operations (struct
drm_framebuffer_funcs). Note that this function
publishes the framebuffer and so from this point on it can be accessed
concurrently from other threads. Hence it must be the last step in the
driver's framebuffer initialization sequence. Frame buffer operations
are
int (*create_handle)(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned int *handle);
Create a handle to the frame buffer underlying memory object. If the frame buffer uses a multi-plane format, the handle will reference the memory object associated with the first plane.
Drivers call drm_gem_handle_create
to create
the handle.
void (*destroy)(struct drm_framebuffer *framebuffer);
Destroy the frame buffer object and frees all associated
resources. Drivers must call
drm_framebuffer_cleanup
to free resources
allocated by the DRM core for the frame buffer object, and must
make sure to unreference all memory objects associated with the
frame buffer. Handles created by the
create_handle
operation are released by
the DRM core.
int (*dirty)(struct drm_framebuffer *framebuffer, struct drm_file *file_priv, unsigned flags, unsigned color, struct drm_clip_rect *clips, unsigned num_clips);
This optional operation notifies the driver that a region of the frame buffer has changed in response to a DRM_IOCTL_MODE_DIRTYFB ioctl call.
The lifetime of a drm framebuffer is controlled with a reference count,
drivers can grab additional references with
drm_framebuffer_reference
and drop them
again with drm_framebuffer_unreference
. For
driver-private framebuffers for which the last reference is never
dropped (e.g. for the fbdev framebuffer when the struct
drm_framebuffer is embedded into the fbdev
helper struct) drivers can manually clean up a framebuffer at module
unload time with
drm_framebuffer_unregister_private
.
The KMS API doesn't standardize backing storage object creation and leaves it to driver-specific ioctls. Furthermore actually creating a buffer object even for GEM-based drivers is done through a driver-specific ioctl - GEM only has a common userspace interface for sharing and destroying objects. While not an issue for full-fledged graphics stacks that include device-specific userspace components (in libdrm for instance), this limit makes DRM-based early boot graphics unnecessarily complex.
Dumb objects partly alleviate the problem by providing a standard API to create dumb buffers suitable for scanout, which can then be used to create KMS frame buffers.
To support dumb objects drivers must implement the
dumb_create
,
dumb_destroy
and
dumb_map_offset
operations.
int (*dumb_create)(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args);
The dumb_create
operation creates a driver
object (GEM or TTM handle) suitable for scanout based on the
width, height and depth from the struct
drm_mode_create_dumb argument. It fills the
argument's handle
,
pitch
and size
fields with a handle for the newly created object and its line
pitch and size in bytes.
int (*dumb_destroy)(struct drm_file *file_priv, struct drm_device *dev, uint32_t handle);
The dumb_destroy
operation destroys a dumb
object created by dumb_create
.
int (*dumb_map_offset)(struct drm_file *file_priv, struct drm_device *dev, uint32_t handle, uint64_t *offset);
The dumb_map_offset
operation associates an
mmap fake offset with the object given by the handle and returns
it. Drivers must use the
drm_gem_create_mmap_offset
function to
associate the fake offset as described in
the section called “GEM Objects Mapping”.
Note that dumb objects may not be used for gpu acceleration, as has been attempted on some ARM embedded platforms. Such drivers really must have a hardware-specific ioctl to allocate suitable buffer objects.
void (*output_poll_changed)(struct drm_device *dev);
This operation notifies the driver that the status of one or more
connectors has changed. Drivers that use the fb helper can just call the
drm_fb_helper_hotplug_event
function to handle this
operation.
Beside some lookup structures with their own locking (which is hidden
behind the interface functions) most of the modeset state is protected
by the dev-<mode_config.lock
mutex and additionally
per-crtc locks to allow cursor updates, pageflips and similar operations
to occur concurrently with background tasks like output detection.
Operations which cross domains like a full modeset always grab all
locks. Drivers there need to protect resources shared between crtcs with
additional locking. They also need to be careful to always grab the
relevant crtc locks if a modset functions touches crtc state, e.g. for
load detection (which does only grab the mode_config.lock
to allow concurrent screen updates on live crtcs).