Skip to content

drm: expose the connector TILE property#2034

Open
algesten wants to merge 1 commit into
Smithay:masterfrom
algesten:cosmic-5k-tile
Open

drm: expose the connector TILE property#2034
algesten wants to merge 1 commit into
Smithay:masterfrom
algesten:cosmic-5k-tile

Conversation

@algesten

Copy link
Copy Markdown

Disclosure: I have done this PR using Claude Code. Whilst I am well versed in Rust (I wrote ureq among other), I know very little about the graphics stack in Linux. I had Claude teach me what I need to know to fix my problem.

I use a LG UltraFine 5K that is about 8 years old and uses tiled DP 1.2 to render 5K. I just now installed PopOS/COSMIC and it doesn't drive my monitor correctly. The monitor is Thunderbolt only, and connected to a Maple Ridge PCIe card that in turn takes two DP cables from my NVIDIA card. I believe the problem is described here (pop-os/cosmic-comp#2295)

The monitor presents itself as two DP streams with two EDID. In the EDID there is a TILE property, which is available in drm, but currently not possible to read from Smithay.

This TILE property contains the necessary info to understand that it's a tiled situation and the DP streams should be rendered to as if two halves of the same screen.

The PR adds backend::drm::TileInfo and DrmDevice::tile_info(), along with the ASCII-blob parser for the kernel format. It is what is needed from Smithay.

I got the full thing working in cosmic-comp locally. group_id, positions (0,0) and (1,0) in a 2x1 grid, tile size 2560x2880.

The first generation of 5K monitors (LG UltraFine 5K, Dell UP2715K,
mid-2010s) couldn't fit 5120x2880@60 down a single DP 1.2 cable and
instead carry the image as two streams, one per tile half. Each half
presents as its own DRM connector, with a DisplayID Tile Topology
block in its EDID describing where it sits in the monitor. The
kernel parses that block and exposes the result as the `TILE`
immutable blob, formatted as eight ':'-delimited decimals:
group_id:flags:num_h_tiles:num_v_tiles:loc_h:loc_v:tile_w:tile_h.

Newer 5K panels carry the image on a single cable using DSC over
DP 1.4, or uncompressed over DP 2.1 UHBR.

`DrmDevice::tile_info()` reads the blob, parses it into a new
`backend::drm::TileInfo` struct, and returns `None` for connectors
without one. Compositors can use the shared `group_id` to identify
connectors that belong to the same physical monitor.

The kernel's `flags` field is parsed and discarded. It isn't
documented and Mutter ignores it.

AI-generated: This code was co-authored with Claude (Anthropic).
@Drakulix

Copy link
Copy Markdown
Member

Hmm. Exposing the TILE property is definitely not wrong, as we need this information to correctly handle this case.

I just wonder if a pure drm-helper in smithay is the right approach or whether we could provide more abstractions for this in smithay and if we perhaps even should.

  • For one I am not sure, if doing separate commits for the two halves can cause tearing between the different parts of the panel or if the two crtcs need to be updated in a single atomic commit for frame-locking to be correctly applied.
  • Are there tiled monitors, which support VRR? that might make this problem even more pronounced as we likely want to drive both at the same refresh rate.
  • So I am thinking we might need to make the DrmCompositor at least support multiple DrmSurfaces. (Ping @cmeissl)
  • If we were to purely provide the TILE-property, this code might be better suited for the smithay-drm-extras crate. (Which I wanted to integrate into cosmic-comp for the longest time anyway, so this would be a good opportunity.)

Either way thanks for working on this. We might just need a little more design work first. Luckily the code you wrote so far for smithay at least is very universally applicable and just needs to be moved around at worst.

@algesten

Copy link
Copy Markdown
Author

@Drakulix thanks!

I just wonder if a pure drm-helper in smithay is the right approach or whether we could provide more abstractions for this in smithay and if we perhaps even should.

Yeah, so to make this work on my monitor, I currently have a hack in cosmic-comp. The halves are rendered side-by-side, but if I change the COSMIC "Orientation" setting, it goes completely screwy. This is because my hack translates the 5120x2880 by subtraction for the right hand half. In a 90-degree orientation the halves are above each other, so it's not X that needs shifting.

* For one I am not sure, if doing separate commits for the two halves can cause tearing between the different parts of the panel or if the two crtcs need to be updated in a single atomic commit for frame-locking to be correctly applied.

That's correct. In discussion with Claude the recommendation is a "subsurface" abstraction in smithay, but I was a bit weary to suggest big API changes in my first ever interaction with your project.

* Are there tiled monitors, which support VRR? that might make this problem even more pronounced as we likely want to drive both at the same refresh rate.

Yeah, I wouldn't know. This is my only 5K monitor :)

* So I am thinking we might need to make the `DrmCompositor` at least support multiple `DrmSurface`s. (Ping @cmeissl)

Sounds like that is the direction and the Bigger Picture (lol).

* If we were to purely provide the TILE-property, this code might be better suited for the `smithay-drm-extras` crate. (Which I wanted to integrate into cosmic-comp for the longest time anyway, so this would be a good opportunity.)

Either way thanks for working on this. We might just need a little more design work first. Luckily the code you wrote so far for smithay at least is very universally applicable and just needs to be moved around at worst.

On some level, I sorted my own problem locally, but I'm also happy to spend effort making this work for others. I'm happy to take your lead on what direction to take.

@Drakulix

Copy link
Copy Markdown
Member

On some level, I sorted my own problem locally, but I'm also happy to spend effort making this work for others. I'm happy to take your lead on what direction to take.

Glad to hear that, because frankly a half-AI-coded personal workaround, isn't really suitable for long-term maintenance and thus inclusion in either project.

So the path forward I am seeing here (as you already figured out) would be to support multiple DrmSurfaces in the DrmCompositor. Probably as a new constructor, something like new_tiled.

(I don't want to introduce "sub"-surfaces to the DrmSurface abstraction, because that represents a single CRTC, not a single connector. We want simple blocks, which can be combined into more sophisticated abstraction, not a single thing that does everything. Furthermore the DrmCompositor would need to be aware of multiple surfaces anyway to handle direct scanout in those cases.)

This means we also need the following changes to the DrmSurface:

  • Read the tile property. (DrmCompositor would read that to figure out the relation of the outputs to another automatically, but the compositor still needs to call this to figure out initially which connectors belong together.)
  • Ability to create a commit spanning multiple surfaces (probably just add a secondary commit and page_flip method to DrmSurface, which you can pass a &mut AtomicModeReq to.)

Does this make some sense?

@algesten

Copy link
Copy Markdown
Author

Does this make some sense?

Makes perfect sense!

Thank you so much for taking the time to point me in the good direction. I'll take a stab at this tomorrow (Saturday).

I'll leave this PR as is, we will see if we close it out or not – I guess I'm not clear on whether new_tiled would make sense without the context of reading TILE from the EDID. But also that can just be me needing to understand the abstractions better, so that might resolve itself once I get my head around it.

Again, thanks!

@algesten

Copy link
Copy Markdown
Author

Just a quick note that I have it working locally now, but since I relied on AI, I need to review commit-by-commit closely before I open any PR.

If anyone is interested what's going on, here are my WIP branches.

@cmeissl

cmeissl commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

First of thanks for working on this!

Before digging deeper I want make sure I understand some of the design decisions correctly.
The whole tile state seems to be built on top of ElementState and FrameState, can you please explain
why you took this route instead of for example making the FrameState and ElementState tile aware?

One thing we should be really careful of is that testing will carry out the same as we do for the commit/pageflip.
As far as I can tell this is currently not the case as each tile is tested independently.

@algesten

algesten commented Jun 8, 2026

Copy link
Copy Markdown
Author

First of thanks for working on this!

Thanks for taking a look!

Before digging deeper I want make sure I understand some of the design decisions correctly. The whole tile state seems to be built on top of ElementState and FrameState, can you please explain why you took this route instead of for example making the FrameState and ElementState tile aware?

I kept it on top of FrameState/ElementState rather than tile-aware on purpose. I didn't want the CRTC level to know anything about the TILE property. A tile is just a DrmSurface with its own planes and swapchain, and the composition sits above that.

I don't know if there is a use case here, but I imagined it would be possible to use the tiled output with several normal screens on the same card too.

One thing we should be really careful of is that testing will carry out the same as we do for the commit/pageflip. As far as I can tell this is currently not the case as each tile is tested independently.

You're right. I'll make a new test using the same DrmAtomicCommit builder so it spans all tiles, rather than make FrameState tile-aware.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants