Skip to main content

gpui_engine/
surface_format.rs

1//! The surface-format vocabulary: every dimension a GPU needs to sample a buffer GPUI did not draw.
2//!
3//! A producer describes the pixels it made so a renderer can sample them. That description is a
4//! *shape* — how the colour is modelled and subsampled, how the planes are laid out, the component
5//! order, the sample depth and the word it is stored in, and what the alpha means. [`SurfaceFormat`]
6//! holds that shape, one private dimension per field; it is built only here, so a `SurfaceFormat`
7//! always describes a shape that exists.
8//!
9//! A producer reaches one through [`SurfaceFormatKind`], an enum that is **a choice of pre-constructed
10//! `SurfaceFormat`s**: each variant names one format a producer emits and carries the shape that
11//! format is. That gives a renderer a closed, exhaustive set to match on — and a format the vocabulary
12//! does not contain cannot be named at all — while the dimensions stay a plain struct a renderer reads.
13//!
14//! What is modelled, and why the model stops where it does, is the `frame-formats.md` chapter under
15//! `spi/rendering/`. Two families are deliberately **not** kinds because this model cannot name them
16//! honestly: **packed YCbCr** (`YUYV`, `Y210`), whose component interleave is a dimension of its own,
17//! and **sub-byte packed RGB** (`RGB565`, `A2R10G10B10`), whose components are not all the same width.
18//! Both are curated in the chapter; neither is a [`SurfaceFormatKind`] yet.
19
20/// How a surface's colour is modelled.
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum ColorModel {
23    /// Luma and chroma, converted to RGB before it is displayed.
24    Yuv,
25    /// RGB, sampled as it is.
26    Rgb,
27}
28
29/// How much colour detail a chroma component carries relative to luma.
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum Subsampling {
32    /// No chroma: a single luma plane.
33    C400,
34    /// 4:1:1 — chroma at a quarter of the horizontal resolution.
35    C411,
36    /// 4:2:0 — chroma at half the resolution in both axes.
37    C420,
38    /// 4:2:2 — chroma at half the horizontal resolution.
39    C422,
40    /// 4:4:4 — chroma at the full resolution.
41    C444,
42}
43
44/// How a surface's planes are arranged.
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum PlaneLayout {
47    /// One plane, the components interleaved.
48    Packed,
49    /// A luma plane, then both chroma components interleaved in a second.
50    SemiPlanar,
51    /// A luma plane, then one plane for each chroma component.
52    Planar,
53}
54
55/// The order of an RGB surface's first two components.
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub enum RgbOrder {
58    /// Red, then green (`RGBA8`).
59    Rgb,
60    /// Blue, then green (`BGRA8`).
61    Bgr,
62}
63
64/// The order of a surface's chroma components, where they share a plane.
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum ChromaOrder {
67    /// Cb before Cr (`NV12`, `I420`).
68    CbCr,
69    /// Cr before Cb (`NV21`, `YV12`).
70    CrCb,
71}
72
73/// The nominal bits of a sample.
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub enum SampleDepth {
76    /// 8 bits.
77    Bits8,
78    /// 10 bits.
79    Bits10,
80    /// 12 bits.
81    Bits12,
82    /// 16 bits.
83    Bits16,
84}
85
86/// The word a sample is stored in.
87#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88pub enum SampleContainer {
89    /// One 8-bit byte, holding the whole sample.
90    U8,
91    /// A 16-bit word; a sample narrower than 16 bits sits in its **high** bits (`P010`, `P012`), as
92    /// every 16-bit-container video format does.
93    U16,
94    /// A 32-bit word holding a packed sample (`Y410`).
95    U32Packed,
96}
97
98/// What a surface's alpha component means, where it has one.
99#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100pub enum Alpha {
101    /// No alpha: the surface is opaque.
102    None,
103    /// Straight (non-premultiplied) alpha.
104    Straight,
105    /// Premultiplied alpha.
106    Premultiplied,
107}
108
109/// Every dimension of a surface format: the full shape a GPU importer needs to sample a buffer.
110///
111/// Built only here — its fields are private and its constructors are private — so it is always one of
112/// the shapes a [`SurfaceFormatKind`] admits, and a renderer reads it rather than inventing it.
113#[derive(Debug, Clone, Copy, PartialEq, Eq)]
114pub struct SurfaceFormat {
115    model: ColorModel,
116    subsampling: Subsampling,
117    layout: PlaneLayout,
118    rgb_order: RgbOrder,
119    chroma_order: ChromaOrder,
120    depth: SampleDepth,
121    container: SampleContainer,
122    alpha: Alpha,
123}
124
125impl SurfaceFormat {
126    /// The RGB shape: one interleaved plane, full "chroma" resolution by definition.
127    const fn rgb(
128        order: RgbOrder,
129        depth: SampleDepth,
130        container: SampleContainer,
131        alpha: Alpha,
132    ) -> Self {
133        Self {
134            model: ColorModel::Rgb,
135            subsampling: Subsampling::C444,
136            layout: PlaneLayout::Packed,
137            rgb_order: order,
138            chroma_order: ChromaOrder::CbCr,
139            depth,
140            container,
141            alpha,
142        }
143    }
144
145    /// The YCbCr shape.
146    const fn yuv(
147        subsampling: Subsampling,
148        layout: PlaneLayout,
149        order: ChromaOrder,
150        depth: SampleDepth,
151        container: SampleContainer,
152    ) -> Self {
153        Self {
154            model: ColorModel::Yuv,
155            subsampling,
156            layout,
157            rgb_order: RgbOrder::Rgb,
158            chroma_order: order,
159            depth,
160            container,
161            alpha: Alpha::None,
162        }
163    }
164
165    /// How the colour is modelled.
166    pub const fn model(&self) -> ColorModel {
167        self.model
168    }
169
170    /// How much colour detail the chroma carries.
171    pub const fn subsampling(&self) -> Subsampling {
172        self.subsampling
173    }
174
175    /// How the planes are arranged.
176    pub const fn layout(&self) -> PlaneLayout {
177        self.layout
178    }
179
180    /// The order of an RGB surface's first two components; meaningless for YCbCr.
181    pub const fn rgb_order(&self) -> RgbOrder {
182        self.rgb_order
183    }
184
185    /// The order of the chroma components; meaningless for RGB.
186    pub const fn chroma_order(&self) -> ChromaOrder {
187        self.chroma_order
188    }
189
190    /// The nominal bits of a sample.
191    pub const fn depth(&self) -> SampleDepth {
192        self.depth
193    }
194
195    /// The word a sample is stored in.
196    pub const fn container(&self) -> SampleContainer {
197        self.container
198    }
199
200    /// What the alpha component means, where the surface has one.
201    pub const fn alpha(&self) -> Alpha {
202        self.alpha
203    }
204
205    /// Whether the colour is YCbCr, and so needs a matrix before it is RGB.
206    pub const fn is_yuv(&self) -> bool {
207        matches!(self.model, ColorModel::Yuv)
208    }
209
210    /// How many planes a buffer of this shape carries: one for packed and mono, two for semi-planar,
211    /// three for planar.
212    pub const fn plane_count(&self) -> usize {
213        match self.subsampling {
214            Subsampling::C400 => 1,
215            _ => match self.layout {
216                PlaneLayout::Packed => 1,
217                PlaneLayout::SemiPlanar => 2,
218                PlaneLayout::Planar => 3,
219            },
220        }
221    }
222}
223
224/// A format a producer emits: a choice of pre-constructed [`SurfaceFormat`]s.
225///
226/// See the module documentation. Name one of the constants ([`NV12`](Self::NV12) and friends) to get
227/// a value; match a variant to tell formats apart.
228#[derive(Debug, Clone, Copy, PartialEq, Eq)]
229pub enum SurfaceFormatKind {
230    /// `BGRA8`: 8-bit blue/green/red/alpha, straight alpha — the common desktop format.
231    Bgra8(SurfaceFormat),
232    /// `RGBA8`: 8-bit red/green/blue/alpha, straight alpha.
233    Rgba8(SurfaceFormat),
234
235    /// `NV12`: 4:2:0 semi-planar, Cb then Cr — the universal decoder default.
236    Nv12(SurfaceFormat),
237    /// `NV21`: `NV12` with the chroma components the other way round.
238    Nv21(SurfaceFormat),
239    /// `I420` (`YU12`): 4:2:0 planar, Cb and Cr in their own planes after luma.
240    I420(SurfaceFormat),
241    /// `YV12`: `I420` with the two chroma planes the other way round.
242    Yv12(SurfaceFormat),
243    /// `NV16`: 4:2:2 semi-planar, Cb then Cr.
244    Nv16(SurfaceFormat),
245    /// `NV61`: `NV16` with the chroma components the other way round.
246    Nv61(SurfaceFormat),
247    /// `YU16`: 4:2:2 planar, Cb then Cr planes.
248    Yu16(SurfaceFormat),
249    /// `YV16`: `YU16` with the two chroma planes the other way round.
250    Yv16(SurfaceFormat),
251    /// `NV24`: 4:4:4 semi-planar, Cb then Cr.
252    Nv24(SurfaceFormat),
253    /// `YUV444`: 4:4:4 planar.
254    Yuv444(SurfaceFormat),
255    /// Mono: a single 8-bit luma plane and no chroma at all.
256    Mono8(SurfaceFormat),
257
258    /// `P010`: 4:2:0 semi-planar, 10 bits in the high bits of a 16-bit word — `HEVC Main10`,
259    /// `VP9` profile 2 and `AV1`.
260    P010(SurfaceFormat),
261    /// `P012`: 4:2:0 semi-planar, 12 bits in a 16-bit word.
262    P012(SurfaceFormat),
263    /// `P016`: 4:2:0 semi-planar, a full 16-bit sample.
264    P016(SurfaceFormat),
265    /// `I010`: 4:2:0 planar, 10 bits in a 16-bit word.
266    I010(SurfaceFormat),
267    /// `I012`: 4:2:0 planar, 12 bits in a 16-bit word.
268    I012(SurfaceFormat),
269    /// `I016`: 4:2:0 planar, a full 16-bit sample.
270    I016(SurfaceFormat),
271    /// `P210`: 4:2:2 semi-planar, 10 bits in a 16-bit word.
272    P210(SurfaceFormat),
273    /// `P212`: 4:2:2 semi-planar, 12 bits in a 16-bit word.
274    P212(SurfaceFormat),
275    /// `P216`: 4:2:2 semi-planar, a full 16-bit sample.
276    P216(SurfaceFormat),
277    /// `P410`: 4:4:4 semi-planar, 10 bits in a 16-bit word.
278    P410(SurfaceFormat),
279    /// `P412`: 4:4:4 semi-planar, 12 bits in a 16-bit word.
280    P412(SurfaceFormat),
281    /// `P416`: 4:4:4 semi-planar, a full 16-bit sample.
282    P416(SurfaceFormat),
283    /// `Q410`: 4:4:4 planar, 10 bits in a 16-bit word.
284    Q410(SurfaceFormat),
285    /// `Q416`: 4:4:4 planar, a full 16-bit sample.
286    Q416(SurfaceFormat),
287}
288
289impl SurfaceFormatKind {
290    /// `BGRA8`: 8-bit blue/green/red/alpha, straight alpha.
291    pub const fn bgra8() -> Self {
292        Self::Bgra8(SurfaceFormat::rgb(
293            RgbOrder::Bgr,
294            SampleDepth::Bits8,
295            SampleContainer::U8,
296            Alpha::Straight,
297        ))
298    }
299
300    /// `RGBA8`: 8-bit red/green/blue/alpha, straight alpha.
301    pub const fn rgba8() -> Self {
302        Self::Rgba8(SurfaceFormat::rgb(
303            RgbOrder::Rgb,
304            SampleDepth::Bits8,
305            SampleContainer::U8,
306            Alpha::Straight,
307        ))
308    }
309
310    /// `NV12`: 4:2:0 semi-planar, Cb then Cr — the universal decoder default.
311    pub const fn nv12() -> Self {
312        Self::Nv12(SurfaceFormat::yuv(
313            Subsampling::C420,
314            PlaneLayout::SemiPlanar,
315            ChromaOrder::CbCr,
316            SampleDepth::Bits8,
317            SampleContainer::U8,
318        ))
319    }
320
321    /// `NV21`: `NV12` with the chroma components the other way round.
322    pub const fn nv21() -> Self {
323        Self::Nv21(SurfaceFormat::yuv(
324            Subsampling::C420,
325            PlaneLayout::SemiPlanar,
326            ChromaOrder::CrCb,
327            SampleDepth::Bits8,
328            SampleContainer::U8,
329        ))
330    }
331
332    /// `I420` (`YU12`): 4:2:0 planar, Cb and Cr in their own planes after luma.
333    pub const fn i420() -> Self {
334        Self::I420(SurfaceFormat::yuv(
335            Subsampling::C420,
336            PlaneLayout::Planar,
337            ChromaOrder::CbCr,
338            SampleDepth::Bits8,
339            SampleContainer::U8,
340        ))
341    }
342
343    /// `YV12`: `I420` with the two chroma planes the other way round.
344    pub const fn yv12() -> Self {
345        Self::Yv12(SurfaceFormat::yuv(
346            Subsampling::C420,
347            PlaneLayout::Planar,
348            ChromaOrder::CrCb,
349            SampleDepth::Bits8,
350            SampleContainer::U8,
351        ))
352    }
353
354    /// `NV16`: 4:2:2 semi-planar, Cb then Cr.
355    pub const fn nv16() -> Self {
356        Self::Nv16(SurfaceFormat::yuv(
357            Subsampling::C422,
358            PlaneLayout::SemiPlanar,
359            ChromaOrder::CbCr,
360            SampleDepth::Bits8,
361            SampleContainer::U8,
362        ))
363    }
364
365    /// `NV61`: `NV16` with the chroma components the other way round.
366    pub const fn nv61() -> Self {
367        Self::Nv61(SurfaceFormat::yuv(
368            Subsampling::C422,
369            PlaneLayout::SemiPlanar,
370            ChromaOrder::CrCb,
371            SampleDepth::Bits8,
372            SampleContainer::U8,
373        ))
374    }
375
376    /// `YU16`: 4:2:2 planar, Cb then Cr planes.
377    pub const fn yu16() -> Self {
378        Self::Yu16(SurfaceFormat::yuv(
379            Subsampling::C422,
380            PlaneLayout::Planar,
381            ChromaOrder::CbCr,
382            SampleDepth::Bits8,
383            SampleContainer::U8,
384        ))
385    }
386
387    /// `YV16`: `YU16` with the two chroma planes the other way round.
388    pub const fn yv16() -> Self {
389        Self::Yv16(SurfaceFormat::yuv(
390            Subsampling::C422,
391            PlaneLayout::Planar,
392            ChromaOrder::CrCb,
393            SampleDepth::Bits8,
394            SampleContainer::U8,
395        ))
396    }
397
398    /// `NV24`: 4:4:4 semi-planar, Cb then Cr.
399    pub const fn nv24() -> Self {
400        Self::Nv24(SurfaceFormat::yuv(
401            Subsampling::C444,
402            PlaneLayout::SemiPlanar,
403            ChromaOrder::CbCr,
404            SampleDepth::Bits8,
405            SampleContainer::U8,
406        ))
407    }
408
409    /// `YUV444`: 4:4:4 planar.
410    pub const fn yuv444() -> Self {
411        Self::Yuv444(SurfaceFormat::yuv(
412            Subsampling::C444,
413            PlaneLayout::Planar,
414            ChromaOrder::CbCr,
415            SampleDepth::Bits8,
416            SampleContainer::U8,
417        ))
418    }
419
420    /// Mono: a single 8-bit luma plane and no chroma at all.
421    pub const fn mono8() -> Self {
422        Self::Mono8(SurfaceFormat::yuv(
423            Subsampling::C400,
424            PlaneLayout::Planar,
425            ChromaOrder::CbCr,
426            SampleDepth::Bits8,
427            SampleContainer::U8,
428        ))
429    }
430
431    /// `P010`: 4:2:0 semi-planar, 10 bits in the high bits of a 16-bit word.
432    pub const fn p010() -> Self {
433        Self::P010(SurfaceFormat::yuv(
434            Subsampling::C420,
435            PlaneLayout::SemiPlanar,
436            ChromaOrder::CbCr,
437            SampleDepth::Bits10,
438            SampleContainer::U16,
439        ))
440    }
441
442    /// `P012`: 4:2:0 semi-planar, 12 bits in a 16-bit word.
443    pub const fn p012() -> Self {
444        Self::P012(SurfaceFormat::yuv(
445            Subsampling::C420,
446            PlaneLayout::SemiPlanar,
447            ChromaOrder::CbCr,
448            SampleDepth::Bits12,
449            SampleContainer::U16,
450        ))
451    }
452
453    /// `P016`: 4:2:0 semi-planar, a full 16-bit sample.
454    pub const fn p016() -> Self {
455        Self::P016(SurfaceFormat::yuv(
456            Subsampling::C420,
457            PlaneLayout::SemiPlanar,
458            ChromaOrder::CbCr,
459            SampleDepth::Bits16,
460            SampleContainer::U16,
461        ))
462    }
463
464    /// `I010`: 4:2:0 planar, 10 bits in a 16-bit word.
465    pub const fn i010() -> Self {
466        Self::I010(SurfaceFormat::yuv(
467            Subsampling::C420,
468            PlaneLayout::Planar,
469            ChromaOrder::CbCr,
470            SampleDepth::Bits10,
471            SampleContainer::U16,
472        ))
473    }
474
475    /// `I012`: 4:2:0 planar, 12 bits in a 16-bit word.
476    pub const fn i012() -> Self {
477        Self::I012(SurfaceFormat::yuv(
478            Subsampling::C420,
479            PlaneLayout::Planar,
480            ChromaOrder::CbCr,
481            SampleDepth::Bits12,
482            SampleContainer::U16,
483        ))
484    }
485
486    /// `I016`: 4:2:0 planar, a full 16-bit sample.
487    pub const fn i016() -> Self {
488        Self::I016(SurfaceFormat::yuv(
489            Subsampling::C420,
490            PlaneLayout::Planar,
491            ChromaOrder::CbCr,
492            SampleDepth::Bits16,
493            SampleContainer::U16,
494        ))
495    }
496
497    /// `P210`: 4:2:2 semi-planar, 10 bits in a 16-bit word.
498    pub const fn p210() -> Self {
499        Self::P210(SurfaceFormat::yuv(
500            Subsampling::C422,
501            PlaneLayout::SemiPlanar,
502            ChromaOrder::CbCr,
503            SampleDepth::Bits10,
504            SampleContainer::U16,
505        ))
506    }
507
508    /// `P212`: 4:2:2 semi-planar, 12 bits in a 16-bit word.
509    pub const fn p212() -> Self {
510        Self::P212(SurfaceFormat::yuv(
511            Subsampling::C422,
512            PlaneLayout::SemiPlanar,
513            ChromaOrder::CbCr,
514            SampleDepth::Bits12,
515            SampleContainer::U16,
516        ))
517    }
518
519    /// `P216`: 4:2:2 semi-planar, a full 16-bit sample.
520    pub const fn p216() -> Self {
521        Self::P216(SurfaceFormat::yuv(
522            Subsampling::C422,
523            PlaneLayout::SemiPlanar,
524            ChromaOrder::CbCr,
525            SampleDepth::Bits16,
526            SampleContainer::U16,
527        ))
528    }
529
530    /// `P410`: 4:4:4 semi-planar, 10 bits in a 16-bit word.
531    pub const fn p410() -> Self {
532        Self::P410(SurfaceFormat::yuv(
533            Subsampling::C444,
534            PlaneLayout::SemiPlanar,
535            ChromaOrder::CbCr,
536            SampleDepth::Bits10,
537            SampleContainer::U16,
538        ))
539    }
540
541    /// `P412`: 4:4:4 semi-planar, 12 bits in a 16-bit word.
542    pub const fn p412() -> Self {
543        Self::P412(SurfaceFormat::yuv(
544            Subsampling::C444,
545            PlaneLayout::SemiPlanar,
546            ChromaOrder::CbCr,
547            SampleDepth::Bits12,
548            SampleContainer::U16,
549        ))
550    }
551
552    /// `P416`: 4:4:4 semi-planar, a full 16-bit sample.
553    pub const fn p416() -> Self {
554        Self::P416(SurfaceFormat::yuv(
555            Subsampling::C444,
556            PlaneLayout::SemiPlanar,
557            ChromaOrder::CbCr,
558            SampleDepth::Bits16,
559            SampleContainer::U16,
560        ))
561    }
562
563    /// `Q410`: 4:4:4 planar, 10 bits in a 16-bit word.
564    pub const fn q410() -> Self {
565        Self::Q410(SurfaceFormat::yuv(
566            Subsampling::C444,
567            PlaneLayout::Planar,
568            ChromaOrder::CbCr,
569            SampleDepth::Bits10,
570            SampleContainer::U16,
571        ))
572    }
573
574    /// `Q416`: 4:4:4 planar, a full 16-bit sample.
575    pub const fn q416() -> Self {
576        Self::Q416(SurfaceFormat::yuv(
577            Subsampling::C444,
578            PlaneLayout::Planar,
579            ChromaOrder::CbCr,
580            SampleDepth::Bits16,
581            SampleContainer::U16,
582        ))
583    }
584
585    /// The pre-constructed shape this kind names.
586    pub const fn dimensions(self) -> SurfaceFormat {
587        match self {
588            Self::Bgra8(format) | Self::Rgba8(format) => format,
589            Self::Nv12(format)
590            | Self::Nv21(format)
591            | Self::I420(format)
592            | Self::Yv12(format)
593            | Self::Nv16(format)
594            | Self::Nv61(format)
595            | Self::Yu16(format)
596            | Self::Yv16(format)
597            | Self::Nv24(format)
598            | Self::Yuv444(format)
599            | Self::Mono8(format) => format,
600            Self::P010(format)
601            | Self::P012(format)
602            | Self::P016(format)
603            | Self::I010(format)
604            | Self::I012(format)
605            | Self::I016(format)
606            | Self::P210(format)
607            | Self::P212(format)
608            | Self::P216(format)
609            | Self::P410(format)
610            | Self::P412(format)
611            | Self::P416(format)
612            | Self::Q410(format)
613            | Self::Q416(format) => format,
614        }
615    }
616
617    /// Whether the colour is YCbCr; see [`SurfaceFormat::is_yuv`].
618    pub const fn is_yuv(self) -> bool {
619        self.dimensions().is_yuv()
620    }
621
622    /// How many planes a buffer of this kind carries; see [`SurfaceFormat::plane_count`].
623    pub const fn plane_count(self) -> usize {
624        self.dimensions().plane_count()
625    }
626}
627
628impl std::fmt::Display for SurfaceFormatKind {
629    /// The format's conventional name, for diagnostics — a dropped surface says which format it was.
630    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
631        f.write_str(match self {
632            Self::Bgra8(_) => "BGRA8",
633            Self::Rgba8(_) => "RGBA8",
634            Self::Nv12(_) => "NV12",
635            Self::Nv21(_) => "NV21",
636            Self::I420(_) => "I420",
637            Self::Yv12(_) => "YV12",
638            Self::Nv16(_) => "NV16",
639            Self::Nv61(_) => "NV61",
640            Self::Yu16(_) => "YU16",
641            Self::Yv16(_) => "YV16",
642            Self::Nv24(_) => "NV24",
643            Self::Yuv444(_) => "YUV444",
644            Self::Mono8(_) => "MONO8",
645            Self::P010(_) => "P010",
646            Self::P012(_) => "P012",
647            Self::P016(_) => "P016",
648            Self::I010(_) => "I010",
649            Self::I012(_) => "I012",
650            Self::I016(_) => "I016",
651            Self::P210(_) => "P210",
652            Self::P212(_) => "P212",
653            Self::P216(_) => "P216",
654            Self::P410(_) => "P410",
655            Self::P412(_) => "P412",
656            Self::P416(_) => "P416",
657            Self::Q410(_) => "Q410",
658            Self::Q416(_) => "Q416",
659        })
660    }
661}
662
663/// One surface format, and every layout a renderer can import for it.
664///
665/// `modifiers` holds each DRM format modifier the importer will bind for this format, with
666/// `DmaBufHandle::LINEAR` present when a linear buffer is accepted. It is what a producer
667/// negotiates with: pass these to the allocator (VA-API's `VASurfaceAttribDRMFormatModifiers`, a
668/// GBM allocator's modifier list) so the buffer it makes is one the renderer can sample.
669#[derive(Debug, Clone, PartialEq, Eq)]
670pub struct DmaBufFormatCapability {
671    /// The format.
672    pub format: SurfaceFormatKind,
673    /// The modifiers accepted for it. Empty means the renderer cannot import the format at all.
674    pub modifiers: Vec<u64>,
675}
676
677impl DmaBufFormatCapability {
678    /// Whether `modifier` is one of the accepted layouts.
679    pub fn supports(&self, modifier: u64) -> bool {
680        self.modifiers.contains(&modifier)
681    }
682}
683
684/// What a renderer can import as a dma-buf surface.
685///
686/// Enumerated on the consumer's device — the renderer's — and handed to producers so they allocate
687/// a layout the renderer accepts rather than discovering a refusal at import time. A format absent
688/// from this report cannot be imported at all; a modifier absent from its entry cannot be bound for
689/// it.
690///
691/// A linear buffer is still checked against the device's own plane layout when it is imported (a
692/// driver samples only the layout it makes), so `DmaBufHandle::LINEAR` means "linear is accepted,
693/// with the device's own offsets and pitches"; a producer gets those from
694/// `gpui_interop::GpuDevice::linear_layout`.
695///
696/// A driver may list a modifier that implies implicit compression the dma-buf does not carry
697/// (Intel's `Y_TILED_CCS`). The report is what the importer will bind, not a promise that the bytes
698/// are uncompressed: a producer allocating under such a modifier must keep the compressed state
699/// valid in the buffer, per `DmaBufHandle`'s contract.
700#[derive(Debug, Clone, PartialEq, Eq, Default)]
701pub struct DmaBufCapabilities {
702    formats: Vec<DmaBufFormatCapability>,
703}
704
705impl DmaBufCapabilities {
706    /// Build the report from the formats the renderer accepts.
707    pub fn new(formats: Vec<DmaBufFormatCapability>) -> Self {
708        Self { formats }
709    }
710
711    /// Every format the renderer can import, with its accepted layouts.
712    pub fn formats(&self) -> &[DmaBufFormatCapability] {
713        &self.formats
714    }
715
716    /// The entry for `format`, if the renderer can import it.
717    pub fn format(&self, format: &SurfaceFormatKind) -> Option<&DmaBufFormatCapability> {
718        self.formats.iter().find(|entry| entry.format == *format)
719    }
720
721    /// The modifiers accepted for `format`, if it can be imported.
722    pub fn modifiers(&self, format: &SurfaceFormatKind) -> Option<&[u64]> {
723        self.format(format).map(|entry| entry.modifiers.as_slice())
724    }
725
726    /// Whether the renderer will bind `format` under `modifier`.
727    pub fn supports(&self, format: &SurfaceFormatKind, modifier: u64) -> bool {
728        self.format(format)
729            .is_some_and(|entry| entry.supports(modifier))
730    }
731}
732
733#[cfg(test)]
734mod tests {
735    use super::*;
736
737    #[test]
738    fn a_packed_rgb_format_is_one_plane_and_not_yuv() {
739        let format = SurfaceFormatKind::bgra8().dimensions();
740        assert_eq!(format.model(), ColorModel::Rgb);
741        assert_eq!(format.rgb_order(), RgbOrder::Bgr);
742        assert_eq!(format.plane_count(), 1);
743        assert!(!format.is_yuv());
744    }
745
746    #[test]
747    fn a_semi_planar_yuv_format_is_two_planes() {
748        let format = SurfaceFormatKind::nv12().dimensions();
749        assert!(format.is_yuv());
750        assert_eq!(format.subsampling(), Subsampling::C420);
751        assert_eq!(format.layout(), PlaneLayout::SemiPlanar);
752        assert_eq!(format.plane_count(), 2);
753        assert_eq!(format.depth(), SampleDepth::Bits8);
754        assert_eq!(SurfaceFormatKind::nv12().plane_count(), 2);
755    }
756
757    #[test]
758    fn a_planar_yuv_format_is_three_planes_bar_mono() {
759        assert_eq!(SurfaceFormatKind::i420().plane_count(), 3);
760        assert_eq!(SurfaceFormatKind::q416().plane_count(), 3);
761        assert_eq!(SurfaceFormatKind::mono8().plane_count(), 1);
762    }
763
764    #[test]
765    fn a_sixteen_bit_container_carries_ten_bits_in_its_high_bits() {
766        let format = SurfaceFormatKind::p010().dimensions();
767        assert_eq!(format.depth(), SampleDepth::Bits10);
768        assert_eq!(format.container(), SampleContainer::U16);
769    }
770
771    #[test]
772    fn the_chroma_orders_differ_only_in_which_component_comes_first() {
773        let cb_cr = SurfaceFormatKind::nv12().dimensions();
774        let cr_cb = SurfaceFormatKind::nv21().dimensions();
775        assert_eq!(cb_cr.chroma_order(), ChromaOrder::CbCr);
776        assert_eq!(cr_cb.chroma_order(), ChromaOrder::CrCb);
777        assert_ne!(cb_cr, cr_cb);
778        assert_eq!(cb_cr.subsampling(), cr_cb.subsampling());
779        assert_eq!(cb_cr.plane_count(), cr_cb.plane_count());
780    }
781
782    #[test]
783    fn a_kind_displays_as_its_conventional_name() {
784        assert_eq!(SurfaceFormatKind::nv12().to_string(), "NV12");
785        assert_eq!(SurfaceFormatKind::p010().to_string(), "P010");
786        assert_eq!(SurfaceFormatKind::bgra8().to_string(), "BGRA8");
787    }
788
789    /// Two kinds are the same only when they name the same format and carry the same shape.
790    #[test]
791    fn kinds_compare_by_their_shape() {
792        assert_eq!(SurfaceFormatKind::nv12(), SurfaceFormatKind::nv12());
793        assert_ne!(SurfaceFormatKind::nv12(), SurfaceFormatKind::nv21());
794        assert_ne!(SurfaceFormatKind::nv12(), SurfaceFormatKind::i420());
795    }
796}