STRUCT DRM_CRTC_STATE(9)
π struct drm_crtc_state(9) β Kernel API Manual π
πΈ NAME πΈ
struct drm_crtc_state β mutable CRTC state. literally the state that can change, bestie.
β¨ SYNOPSIS β¨
struct drm_crtc_state {
struct drm_crtc *crtc;
bool enable;
bool active;
bool planes_changed : 1;
bool mode_changed : 1;
bool active_changed : 1;
bool connectors_changed : 1;
bool zpos_changed : 1;
bool color_mgmt_changed : 1;
bool no_vblank;
u32 plane_mask;
u32 connector_mask;
u32 encoder_mask;
struct drm_display_mode adjusted_mode;
struct drm_display_mode mode;
struct drm_property_blob *mode_blob;
struct drm_property_blob *degamma_lut;
struct drm_property_blob *ctm;
struct drm_property_blob *gamma_lut;
u64 background_color;
u32 target_vblank;
bool async_flip;
bool vrr_enabled;
bool self_refresh_active;
enum drm_scaling_filter scaling_filter;
u8 sharpness_strength;
struct drm_pending_vblank_event *event;
struct drm_crtc_commit *commit;
struct drm_atomic_commit *state;
};
π Members π
okay bestie, member-by-member tea time. every field gets its moment, no skips, no cap π
crtcβ backpointer to the CRTC.enableβ whether the CRTC should be enabled, and it gates all the other state. This controls reservations of shared resources. Actual hardware state is controlled byactive.activeβ whether the CRTC is actively displaying (used for DPMS). It implies thatenableis set. The driver must not release any shared resources ifactiveis set to false butenableis still true, because userspace expects that a DPMS ON always succeeds.
π¨ real talk: hence drivers must not consultactivein their variousdrm_mode_config_funcs.atomic_checkcallback to reject an atomic commit. They can consult it to aid in the computation of derived hardware state, since even in the DPMS OFF state the display hardware should be as much powered down as when the CRTC is completely disabled through settingenableto false.
planes_changedβ planes on this crtc are updated. Used by the atomic helpers and drivers to steer the atomic commit control flow.mode_changedβmodeorenablehas been changed. Used by the atomic helpers and drivers to steer the atomic commit control flow. See alsodrm_atomic_crtc_needs_modeset.
Drivers are supposed to set this for any CRTC state changes that require a full modeset. They can also reset it to false if e.g. a mode change can be done without a full modeset by only changing scaler settings.
active_changedβactivehas been toggled. Used by the atomic helpers and drivers to steer the atomic commit control flow. See alsodrm_atomic_crtc_needs_modeset.connectors_changedβ connectors to this crtc have been updated, either in their state or routing. Used by the atomic helpers and drivers to steer the atomic commit control flow. See alsodrm_atomic_crtc_needs_modeset.
Drivers are supposed to set this as-needed from their own atomic check code, e.g. from drm_encoder_helper_funcs.atomic_check.
zpos_changedβ zpos values of planes on this crtc have been updated. Used by the atomic helpers and drivers to steer the atomic commit control flow.color_mgmt_changedβ color management properties have changed (gamma_lut,degamma_lutorctm). Used by the atomic helpers and drivers to steer the atomic commit control flow.no_vblankβ reflects the ability of a CRTC to send VBLANK events. This state usually depends on the pipeline configuration. If set to true, DRM atomic helpers will send out a fake VBLANK event during display updates after all hardware changes have been committed. This is implemented indrm_atomic_helper_fake_vblank.
One usage is for drivers and/or hardware without support for VBLANK interrupts. Such drivers typically do not initialize vblanking (i.e., call drm_vblank_init with the number of CRTCs). For CRTCs without initialized vblanking, this field is set to true in drm_atomic_helper_check_modeset, and a fake VBLANK event will be send out on each update of the display pipeline by drm_atomic_helper_fake_vblank.
Another usage is CRTCs feeding a writeback connector operating in oneshot mode. In this case the fake VBLANK event is only generated when a job is queued to the writeback connector, and we want the core to fake VBLANK events when this part of the pipeline hasn't changed but others had or when the CRTC and connectors are being disabled.
__drm_atomic_helper_crtc_duplicate_state will not reset the value from the current state, the CRTC driver is then responsible for updating this field when needed.
π«Ά note: the combination ofdrm_crtc_state.event == NULLanddrm_crtc_state.no_blank == trueis valid and usually used when the writeback connector attached to the CRTC has a new job queued. In this case the driver will send the VBLANK event on its own when the writeback job is complete.
plane_maskβ bitmask ofdrm_plane_mask(plane)of planes attached to this CRTC.connector_maskβ bitmask ofdrm_connector_mask(connector)of connectors attached to this CRTC.encoder_maskβ bitmask ofdrm_encoder_mask(encoder)of encoders attached to this CRTC.adjusted_modeβ internal display timings which can be used by the driver to handle differences between the mode requested by userspace inmodeand what is actually programmed into the hardware.
For drivers using drm_bridge, this stores hardware display timings used between the CRTC and the first bridge. For other drivers, the meaning of the adjusted_mode field is purely driver implementation defined information, and will usually be used to store the hardware display timings used between the CRTC and encoder blocks.
modeβ display timings requested by userspace. The driver should try to match the refresh rate as close as possible (but note that it's undefined what exactly is close enough, e.g. some of the HDMI modes only differ in less than 1% of the refresh rate). The active width and height as observed by userspace for positioning planes must match exactly.
For external connectors where the sink isn't fixed (like with a built-in panel), this mode here should match the physical mode on the wire to the last details (i.e. including sync polarities and everything).
mode_blobβdrm_property_blobformode, for exposing the mode to atomic userspace.degamma_lutβ lookup table for converting framebuffer pixel data before apply the color conversion matrixctm. Seedrm_crtc_enable_color_mgmt. The blob (if not NULL) is an array ofstruct drm_color_lut.ctmβ color transformation matrix. Seedrm_crtc_enable_color_mgmt. The blob (if not NULL) is astruct drm_color_ctm.gamma_lutβ lookup table for converting pixel data after the color conversion matrixctm. Seedrm_crtc_enable_color_mgmt. The blob (if not NULL) is an array ofstruct drm_color_lut.
π fun fact: for mostly historical reasons stemming from Xorg heritage, this is also used to store the color map (also sometimes color lut, CLUT or color palette) for indexed formats like DRM_FORMAT_C8.
background_colorβ RGB value representing the CRTC's background color. The background color (aka "canvas color") of a CRTC is the color that will be used for pixels not covered by a plane, or covered by transparent pixels of a plane. The value here should be built usingDRM_ARGB64_PREP*()helpers, while the individual color components can be extracted with desired precision via theDRM_ARGB64_GET*()macros.target_vblankβ target vertical blank period when a page flip should take effect.async_flipβ this is set whenDRM_MODE_PAGE_FLIP_ASYNCis set in the legacy PAGE_FLIP IOCTL. It's not wired up for the atomic IOCTL itself yet.vrr_enabledβ indicates if variable refresh rate should be enabled for the CRTC. Support for the requested vrr state will depend on driver and hardware capabiltiy β lacking support is not treated as failure.self_refresh_activeβ used by the self refresh helpers to denote when a self refresh transition is occurring. This will be set on enable/disable callbacks when self refresh is being enabled or disabled. In some cases, it may not be desirable to fully shut off the crtc during self refresh. CRTC's can inspect this flag and determine the best course of action.scaling_filterβ scaling filter to be applied.sharpness_strengthβ used by the user to set the sharpness intensity. The value ranges from 0-255. Default value is 0 which disable the sharpness feature. Any value greater than 0 enables sharpening with the specified strength.eventβ optional pointer to a DRM event to signal upon completion of the state update. The driver must send out the event when the atomic commit operation completes. There are two cases:- The event is for a CRTC which is being disabled through this atomic commit. In that case the event can be send out any time after the hardware has stopped scanning out the current framebuffers. It should contain the timestamp and counter for the last vblank before the display pipeline was shut off. The simplest way to achieve that is calling
drm_crtc_send_vblank_eventsomewhen afterdrm_crtc_vblank_offhas been called. - For a CRTC which is enabled at the end of the commit (even when it undergoes an full modeset) the vblank timestamp and counter must be for the vblank right before the first frame that scans out the new set of buffers. Again the event can only be sent out after the hardware has stopped scanning out the old buffers.
- Events for disabled CRTCs are not allowed, and drivers can ignore that case.
- The event is for a CRTC which is being disabled through this atomic commit. In that case the event can be send out any time after the hardware has stopped scanning out the current framebuffers. It should contain the timestamp and counter for the last vblank before the display pipeline was shut off. The simplest way to achieve that is calling
Okay bestie, so for the super-simple hardware that literally doesn't even have a VBLANK interrupt to its name, you can set drm_crtc_state.no_vblank and DRM's atomic commit helpers will justβ¦ make one up for you π. Like, they send a fake VBLANK event at the end of the display update, after every single hardware change has already been applied. It's giving "manifesting a vblank." Go peep drm_atomic_helper_fake_vblank for the deets β¨.
Now for the fancier hardware out there π
β the kind that actually has opinions β this whole thing can be handled by the drm_crtc_send_vblank_event function. Your driver should call it on the provided event once the atomic commit is done, no cap. But heads up: if your driver supports vblank signalling and timestamping, then those vblank counters and timestamps must agree with the ones that come back from page flip events. Like, they have to match, fr fr. With the current vblank helper infrastructure you get there by holding a vblank reference while the page flip is pending β grab it with drm_crtc_vblank_get and release it with drm_crtc_vblank_put. Drivers are totally free to roll their own vblank counter and timestamp tracking though, lowkey iconic behaviour β e.g. if they've got accurate timestamp registers sitting right there in the hardware π¦.
And for hardware that supports some means of synchronizing vblank interrupt delivery with committing display state, there's also drm_crtc_arm_vblank_event π. Go read that function's docs for the full detailed discussion of the constraints β you have to follow them to use it safely, so don't skip it, bestie π.
If the device can't notify of flip completion in a race-free way at all? Then the event should be armed just after the page flip is committed. Worst case, the driver sends the event to userspace one frame too late π. That does not let you do a real atomic update β but it should avoid tearing, which is the whole point. Vibes preserved. β¨
commitβ this one tracks how the commit for this update proceeds through the various phases. It is never cleared, except when we destroy the state, so that subsequent commits can synchronize with previous ones. Loyal to the end π«Ά.stateβ a backpointer to the globaldrm_atomic_commit.
πΈ Description πΈ
So the distinction between enable and active is rather subtle β I'm literally warning you π. Flipping active while enable is set, without changing anything else, may never return a failure from the drm_mode_config_funcs.atomic_check callback. Userspace just assumes a DPMS On will always succeed. In other words, iykyk: enable controls resource assignment, active controls the actual hardware state π
.
The three booleans active_changed, connectors_changed and mode_changed are there to indicate whether a full modeset is needed β rather than strictly describing what has actually changed in a commit. So like, don't read them as a changelog, read them as a vibe check π₯. See also: drm_atomic_crtc_needs_modeset.
β SEE ALSO β
Kernel file ./include/drm/drm_crtc.h plus the whole squad:
struct drm_crtc_funcs(9)struct drm_crtc(9)struct drm_mode_set(9)drmm_crtc_alloc_with_planes(9)drm_crtc_index(9)drm_crtc_mask(9)drm_crtc_find(9)drm_for_each_crtc(9)drm_for_each_crtc_reverse(9)
And that's the whole page, bestie β you ate that π. This one lives in ./include/drm, dated October 2026, and it's serving struct drm_crtc_state(9) energy from start to finish. Go forth and commit atomically πβ¨
π¦ where this page comes from
- nixpkgs unstable: linux-manual 7.3.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms