Skip to content

Conversation

@Drakulix
Copy link
Member

This is an attempt to make the multigpu renderer a bit more flexible, if the sets of formats of two gpus just don't align.

Firstly it makes the dma_shadow_copy try more formats, if the original one isn't available. First it tries to find one with the same bpp (falling back to 8, if it can't be determined, which allows us to finally display something for YUV-formats, even if not accurate) and then it accepts losing precision down to 8-bits per color.

Secondly if the mem_copy-code fails to read from a texture, we currently have no fall back. ExportMem::can_read_texture is meant to prevent that, but on OpenGL ES we can only try to truly see if reading works. Sadly the nvidia driver doesn't allow us to read with GL_RGBA and GL_UNSIGNED_INT_2_10_10_10_REV (it falls with INVALID_OPERATION) even though the spec says it should(?): https://docs.gl/es3/glReadPixels.

This is in particular a problem with games not going through PRIME (e.g. via wine-wayland) which like to allocate their framebuffer in XBGR2101010. So as a fall back we render these into a Abgr8888 shadow buffer and copy from there (which works fine in my testing, even though we obviously lose some precision).

Ideally we should have a vulkan renderer, where none of this is an issue and we can use dmabuf-sharing even with nvidia with Linear-modifiers, but in the meantime this is better than a black window.

@Drakulix Drakulix requested review from cmeissl and ids1024 December 18, 2025 16:23
Copy link
Collaborator

@cmeissl cmeissl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Probably unrelated, but one thing I noticed during re-reading the code is that the else branch in dma_shadow_copy for the slot might return the wrong thing.

If the src format changes the condition .is_some_and(|(buffer, _, _)| buffer.format().code == format) will be false and enter the else branch.
But at the end of the else branch we got (slot.get_or_insert((shadow_buffer, target_texture, None)), true), returning the original slot value instead.

@Drakulix
Copy link
Member Author

LGTM

Probably unrelated, but one thing I noticed during re-reading the code is that the else branch in dma_shadow_copy for the slot might return the wrong thing.

If the src format changes the condition .is_some_and(|(buffer, _, _)| buffer.format().code == format) will be false and enter the else branch. But at the end of the else branch we got (slot.get_or_insert((shadow_buffer, target_texture, None)), true), returning the original slot value instead.

Good observation, I pushed a commit to fix that, though I am not 100% certain we can actually hit this in the cases where dma_shadow_copy is currently called, due to the fact, that the src_texture can't easily change it's format and the slot is usually cached with the texture in question. But this is a freestanding function, so it is good to fix it.

Given this is a very simple one-liner fix, I am taking the liberty of merging the PR as is.

@Drakulix Drakulix merged commit 5aec832 into master Dec 23, 2025
13 checks passed
@Drakulix Drakulix deleted the feat/multigpu-format-fallback branch December 23, 2025 14:56
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