makepad_platform/os/linux/
dma_buf.rs

1#![allow(dead_code)]
2//! # Linux cross-process DMA-BUF-based image ("texture") sharing
3//!
4//! An [`Image<FD>`] primarily contains [DMA-BUF] (`FD`-typed) file descriptor(s)
5//! (within each [`ImagePlane<FD>`], which also tracks its buffer's "2D slice"),
6//! and the ["DRM format"] ([`DrmFormat`]) describing the image's texel encoding,
7//! all combined into a conveniently (de)serializable form (as long as `FD` is).
8//!
9//! ---
10//!
11//! Under EGL, this allows sharing an OpenGL texture across processes, e.g.:
12//! * A creates an `EGLImage` from some OpenGL texture (or another resource)
13//! * A exports its `EGLImage` using [`EGL_MESA_image_dma_buf_export`]
14//! * A passes to B its [DMA-BUF] file descriptor(s) and ["DRM format"] metadata
15//! * B imports it as an `EGLImage` using [`EGL_EXT_image_dma_buf_import`]
16//! * B exposes its `EGLImage` as an OpenGL texture using [`glEGLImageTargetTexture2DOES`]
17//!
18//! [DMA-BUF]: https://docs.kernel.org/driver-api/dma-buf.html
19//! ["DRM format"]: https://docs.kernel.org/gpu/drm-kms.html#drm-format-handling
20//! [`EGL_MESA_image_dma_buf_export`]: https://registry.khronos.org/EGL/extensions/MESA/EGL_MESA_image_dma_buf_export.txt
21//! [`EGL_EXT_image_dma_buf_import`]: https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import.txt
22//! [`glEGLImageTargetTexture2DOES`]: https://registry.khronos.org/OpenGL/extensions/OES/OES_EGL_image.txt
23
24use crate::makepad_micro_serde::*;
25
26#[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
27pub struct Image<FD>
28    // HACK(eddyb) hint `{Ser,De}{Bin,Json}` derivers to add their own bounds.
29    where FD: Sized
30{
31    pub drm_format: DrmFormat,
32    // FIXME(eddyb) support 2-4 planes (not needed for RGBA, so most likely only
33    // relevant to YUV video decode streams - or certain forms of compression).
34    pub planes: ImagePlane<FD>,
35}
36
37impl<FD> Image<FD> {
38    pub fn planes_fd_map<FD2>(self, f: impl FnMut(FD) -> FD2) -> Image<FD2> {
39        let Image { drm_format, planes: plane0 } = self;
40        Image { drm_format, planes: plane0.fd_map(f) }
41    }
42}
43
44/// In the Linux DRM+KMS system (i.e. kernel-side GPU drivers), a "DRM format"
45/// is an image format (i.e. a specific byte-level encoding of texel data)
46/// that framebuffers (or more generally "surfaces" / "images") could use,
47/// provided that all the GPUs involved support the specific format used.
48///
49/// See also <https://docs.kernel.org/gpu/drm-kms.html#drm-format-handling>.
50#[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
51pub struct DrmFormat {
52    /// FourCC code for a "DRM format", i.e. one of the `DRM_FORMAT_*` values
53    /// defined in `drm/drm_fourcc.h`, and the main aspect of a "DRM format"
54    /// that userspace needs to care about (e.g. RGB vs YUV, bit width, etc.).
55    ///
56    /// For example, non-HDR RGBA surfaces will almost always use the format
57    /// `DRM_FORMAT_ABGR8888` (with FourCC `"AB24"`, i.e. `0x34324241`), and:
58    /// - "A" can be replaced with "X" (disabling the alpha channel)
59    /// - "AB" can be reversed, to get "BA" (ABGR -> BGRA)
60    /// - "B" can be replaced with "R" (ABGR -> ARGB)
61    /// - "AR" can be reversed, to get "RA" (ARGB -> RGBA)
62    /// - "24" can be replaced with "30" or "48" (increasing bits per channel)
63    ///
64    /// Some formats also require multiple "planes" (i.e. independent buffers),
65    /// and while that's commonly for YUV formats, planar RGBA also exists.
66    pub fourcc: u32,
67
68    /// Each "DRM format" may be further "modified" with additional features,
69    /// describing how memory is accessed by GPU texture units (e.g. "tiling"),
70    /// and optionally requiring additional "planes" for compression purposes.
71    ///
72    /// To userspace, the modifiers are almost always opaque and merely need to
73    /// be passed from an image exporter to an image importer, to correctly
74    /// interpret the GPU memory in the same way on both sides.
75    pub modifiers: u64,
76}
77
78#[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
79pub struct ImagePlane<FD>
80    // HACK(eddyb) hint `{Ser,De}{Bin,Json}` derivers to add their own bounds.
81    where FD: Sized
82{
83    /// Linux DMA-BUF file descriptor, representing a generic GPU buffer object.
84    ///
85    /// See also <https://docs.kernel.org/driver-api/dma-buf.html>.
86    pub dma_buf_fd: FD,
87
88    /// This plane's starting position (in bytes), in the DMA-BUF buffer.
89    pub offset: u32,
90
91    /// This plane's stride (aka "pitch") for texel rows, in the DMA-BUF buffer.
92    pub stride: u32,
93}
94
95impl<FD> ImagePlane<FD> {
96    fn fd_map<FD2>(self, f: impl FnOnce(FD) -> FD2) -> ImagePlane<FD2> {
97        let ImagePlane { dma_buf_fd, offset, stride } = self;
98        ImagePlane { dma_buf_fd: f(dma_buf_fd), offset, stride }
99    }
100}