1use std::marker::PhantomData;
6
7use libdisplay_info_derive::FFIFrom;
8
9use crate::{edid::ExtensionRef, ffi, FFIIter};
10
11pub struct DisplayId<'ext> {
12 display_id: *const ffi::displayid::di_displayid,
13 phantom: PhantomData<&'ext ()>,
14}
15
16impl<'ext> DisplayId<'ext> {
17 pub fn from_extension(extensions: &'ext ExtensionRef) -> Option<DisplayId<'ext>> {
21 let display_id = unsafe { ffi::edid::di_edid_ext_get_displayid(extensions.as_ptr()) };
22
23 if display_id.is_null() {
24 None
25 } else {
26 Some(Self {
27 display_id: display_id as *const ffi::displayid::di_displayid,
28 phantom: PhantomData,
29 })
30 }
31 }
32
33 pub fn version(&self) -> i32 {
35 unsafe { ffi::displayid::di_displayid_get_version(self.display_id) }
36 }
37
38 pub fn revision(&self) -> i32 {
40 unsafe { ffi::displayid::di_displayid_get_revision(self.display_id) }
41 }
42
43 pub fn product_type(&self) -> ProductType {
45 ProductType::from(unsafe { ffi::displayid::di_displayid_get_product_type(self.display_id) })
46 }
47
48 pub fn data_blocks(&self) -> &[DataBlockRef] {
50 let data_blocks = unsafe { ffi::displayid::di_displayid_get_data_blocks(self.display_id) };
51
52 let mut len = 0;
53 while !unsafe { *data_blocks.offset(len) }.is_null() {
54 len += 1;
55 }
56
57 unsafe { std::slice::from_raw_parts(data_blocks as *const DataBlockRef, len as usize) }
58 }
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, FFIFrom)]
63#[ffi(ffi::displayid::di_displayid_product_type)]
64#[repr(u32)]
65pub enum ProductType {
66 Extension = ffi::displayid::di_displayid_product_type_DI_DISPLAYID_PRODUCT_TYPE_EXTENSION,
67 Test = ffi::displayid::di_displayid_product_type_DI_DISPLAYID_PRODUCT_TYPE_TEST,
68 DisplayPanel =
69 ffi::displayid::di_displayid_product_type_DI_DISPLAYID_PRODUCT_TYPE_DISPLAY_PANEL,
70 StandaloneDisplay =
71 ffi::displayid::di_displayid_product_type_DI_DISPLAYID_PRODUCT_TYPE_STANDALONE_DISPLAY,
72 TvReceiver = ffi::displayid::di_displayid_product_type_DI_DISPLAYID_PRODUCT_TYPE_TV_RECEIVER,
73 Repeater = ffi::displayid::di_displayid_product_type_DI_DISPLAYID_PRODUCT_TYPE_REPEATER,
74 DirectDrive = ffi::displayid::di_displayid_product_type_DI_DISPLAYID_PRODUCT_TYPE_DIRECT_DRIVE,
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, FFIFrom)]
79#[ffi(ffi::displayid::di_displayid_product_type)]
80#[repr(u32)]
81pub enum DataBlockTag {
82 ProductId = ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_PRODUCT_ID,
83 DisplayParams =
84 ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_DISPLAY_PARAMS,
85 ColorCharact =
86 ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_COLOR_CHARACT,
87 TypeITiming = ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_TYPE_I_TIMING,
88 TypeIITiming =
89 ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_TYPE_II_TIMING,
90 TypeIIITiming =
91 ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_TYPE_III_TIMING,
92 TypIVTiming =
93 ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_TYPE_IV_TIMING,
94 VesaTiming = ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_VESA_TIMING,
95 CeaTiming = ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_CEA_TIMING,
96 TimingRangeLimits =
97 ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_TIMING_RANGE_LIMITS,
98 ProductSerial =
99 ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_PRODUCT_SERIAL,
100 AsciiString = ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_ASCII_STRING,
101 DisplayDeviceData =
102 ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_DISPLAY_DEVICE_DATA,
103 InterfacePowerSeq =
104 ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_INTERFACE_POWER_SEQ,
105 TransferCharact =
106 ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_TRANSFER_CHARACT,
107 DisplayInterface =
108 ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_DISPLAY_INTERFACE,
109 StereoDisplayInterface = ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_STEREO_DISPLAY_INTERFACE,
110 TypeVTiming = ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_TYPE_V_TIMING,
111 TiledDisplayTopo =
112 ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_TILED_DISPLAY_TOPO,
113 TypeVITiming =
114 ffi::displayid::di_displayid_data_block_tag_DI_DISPLAYID_DATA_BLOCK_TYPE_VI_TIMING,
115}
116
117#[repr(transparent)]
119pub struct DataBlockRef(*const ffi::displayid::di_displayid_data_block);
120
121impl DataBlockRef {
122 pub fn tag(&self) -> DataBlockTag {
124 DataBlockTag::from(unsafe { ffi::displayid::di_displayid_data_block_get_tag(self.0) })
125 }
126
127 pub fn display_params(&self) -> Option<DisplayParams> {
132 DisplayParams::from_ptr(unsafe {
133 ffi::displayid::di_displayid_data_block_get_display_params(self.0)
134 })
135 }
136
137 pub fn type_i_timings(&self) -> impl Iterator<Item = TypeIIIVIITiming> {
141 FFIIter::new(unsafe { ffi::displayid::di_displayid_data_block_get_type_i_timings(self.0) })
142 }
143
144 #[cfg(any(feature = "v0_2", feature = "v0_3"))]
148 pub fn type_ii_timings(&self) -> impl Iterator<Item = TypeIIIVIITiming> {
149 FFIIter::new(unsafe { ffi::displayid::di_displayid_data_block_get_type_ii_timings(self.0) })
150 }
151
152 #[cfg(any(feature = "v0_2", feature = "v0_3"))]
156 pub fn type_iii_timings(&self) -> impl Iterator<Item = TypeIIITiming> {
157 FFIIter::new(unsafe {
158 ffi::displayid::di_displayid_data_block_get_type_iii_timings(self.0)
159 })
160 }
161
162 pub fn tiled_topo(&self) -> Option<TiledTopo> {
167 TiledTopo::from_ptr(unsafe {
168 ffi::displayid::di_displayid_data_block_get_tiled_topo(self.0)
169 })
170 }
171}
172
173#[derive(Debug, Copy, Clone, FFIFrom)]
175#[ffi(ffi::displayid::di_displayid_display_params_features)]
176pub struct DisplayParamsFeatures {
177 pub audio: bool,
178 pub separate_audio_inputs: bool,
179 pub audio_input_override: bool,
180 pub power_management: bool,
181 pub fixed_timing: bool,
182 pub fixed_pixel_format: bool,
183 pub ai: bool,
184 pub deinterlacing: bool,
185}
186
187#[derive(Debug, Copy, Clone, FFIFrom)]
189#[ffi(ffi::displayid::di_displayid_display_params)]
190pub struct DisplayParams {
191 pub horiz_image_mm: f32,
192 pub vert_image_mm: f32,
193 pub horiz_pixels: i32,
194 pub vert_pixels: i32,
195 #[ptr_deref]
196 pub features: Option<DisplayParamsFeatures>,
197 #[optional(0f32)]
198 pub gamma: Option<f32>,
199 pub aspect_ratio: f32,
200 pub bits_per_color_overall: i32,
201 pub bits_per_color_native: i32,
202}
203
204#[derive(Debug, Clone, Copy, PartialEq, Eq, FFIFrom)]
205#[ffi(ffi::displayid::di_displayid_type_i_ii_vii_timing_stereo_3d)]
206#[repr(u32)]
207pub enum TypeIIIVIITimingStereo3d {
208 Never = ffi::displayid::di_displayid_type_i_ii_vii_timing_stereo_3d_DI_DISPLAYID_TYPE_I_II_VII_TIMING_STEREO_3D_NEVER,
209 Always = ffi::displayid::di_displayid_type_i_ii_vii_timing_stereo_3d_DI_DISPLAYID_TYPE_I_II_VII_TIMING_STEREO_3D_ALWAYS,
210 User = ffi::displayid::di_displayid_type_i_ii_vii_timing_stereo_3d_DI_DISPLAYID_TYPE_I_II_VII_TIMING_STEREO_3D_USER,
211}
212
213#[derive(Debug, Clone, Copy, PartialEq, Eq, FFIFrom)]
214#[ffi(ffi::displayid::di_displayid_timing_aspect_ratio)]
215#[repr(u32)]
216pub enum TimingAspectRatio {
217 _1_1 = ffi::displayid::di_displayid_timing_aspect_ratio_DI_DISPLAYID_TIMING_ASPECT_RATIO_1_1,
218 _5_4 = ffi::displayid::di_displayid_timing_aspect_ratio_DI_DISPLAYID_TIMING_ASPECT_RATIO_5_4,
219 _4_3 = ffi::displayid::di_displayid_timing_aspect_ratio_DI_DISPLAYID_TIMING_ASPECT_RATIO_4_3,
220 _15_9 = ffi::displayid::di_displayid_timing_aspect_ratio_DI_DISPLAYID_TIMING_ASPECT_RATIO_15_9,
221 _16_9 = ffi::displayid::di_displayid_timing_aspect_ratio_DI_DISPLAYID_TIMING_ASPECT_RATIO_16_9,
222 _16_10 =
223 ffi::displayid::di_displayid_timing_aspect_ratio_DI_DISPLAYID_TIMING_ASPECT_RATIO_16_10,
224 _64_27 =
225 ffi::displayid::di_displayid_timing_aspect_ratio_DI_DISPLAYID_TIMING_ASPECT_RATIO_64_27,
226 _256_135 =
227 ffi::displayid::di_displayid_timing_aspect_ratio_DI_DISPLAYID_TIMING_ASPECT_RATIO_256_135,
228 Undefined =
229 ffi::displayid::di_displayid_timing_aspect_ratio_DI_DISPLAYID_TIMING_ASPECT_RATIO_UNDEFINED,
230}
231
232#[derive(Debug, Clone, Copy, PartialEq, Eq, FFIFrom)]
233#[ffi(ffi::displayid::di_displayid_type_i_ii_vii_timing_sync_polarity)]
234#[repr(u32)]
235pub enum TypeIIIVIITimingSyncPolarity {
236 Negative = ffi::displayid::di_displayid_type_i_ii_vii_timing_sync_polarity_DI_DISPLAYID_TYPE_I_II_VII_TIMING_SYNC_NEGATIVE,
237 Positive = ffi::displayid::di_displayid_type_i_ii_vii_timing_sync_polarity_DI_DISPLAYID_TYPE_I_II_VII_TIMING_SYNC_POSITIVE,
238}
239
240#[derive(Debug, Copy, Clone, FFIFrom)]
242#[ffi(ffi::displayid::di_displayid_type_i_ii_vii_timing)]
243pub struct TypeIIIVIITiming {
244 pub pixel_clock_mhz: f64,
245 pub preferred: bool,
246 pub stereo_3d: TypeIIIVIITimingStereo3d,
247 pub interlaced: bool,
248 pub aspect_ratio: TimingAspectRatio,
249 pub horiz_active: i32,
250 pub vert_active: i32,
251 pub horiz_blank: i32,
252 pub vert_blank: i32,
253 pub horiz_offset: i32,
254 pub vert_offset: i32,
255 pub horiz_sync_width: i32,
256 pub vert_sync_width: i32,
257 pub horiz_sync_polarity: TypeIIIVIITimingSyncPolarity,
258 pub vert_sync_polarity: TypeIIIVIITimingSyncPolarity,
259}
260
261#[derive(Debug, Clone, Copy, PartialEq, Eq, FFIFrom)]
263#[ffi(ffi::displayid::di_displayid_type_iii_timing_algo)]
264#[repr(u32)]
265#[cfg(any(feature = "v0_2", feature = "v0_3"))]
266pub enum TyoeIIITimingAlgo {
267 CvtStandardBlanking = ffi::displayid::di_displayid_type_iii_timing_algo_DI_DISPLAYID_TYPE_III_TIMING_CVT_STANDARD_BLANKING,
268 CvtReducedBlacking = ffi::displayid::di_displayid_type_iii_timing_algo_DI_DISPLAYID_TYPE_III_TIMING_CVT_REDUCED_BLANKING,
269}
270
271#[derive(Debug, Copy, Clone, FFIFrom)]
273#[ffi(ffi::displayid::di_displayid_type_iii_timing)]
274#[cfg(any(feature = "v0_2", feature = "v0_3"))]
275pub struct TypeIIITiming {
276 pub preferred: bool,
277 pub algo: TyoeIIITimingAlgo,
278 pub aspect_ratio: TimingAspectRatio,
279 pub horiz_active: i32,
280 pub interlaced: bool,
281 pub refresh_rate_hz: i32,
282}
283
284#[derive(Debug, Clone, Copy, PartialEq, Eq, FFIFrom)]
287#[ffi(ffi::displayid::di_displayid_tiled_topo_missing_recv_behavior)]
288#[repr(u32)]
289pub enum TiledTopoMissingRecvBehavior {
290 Undef = ffi::displayid::di_displayid_tiled_topo_missing_recv_behavior_DI_DISPLAYID_TILED_TOPO_MISSING_RECV_UNDEF,
291 TileOnly = ffi::displayid::di_displayid_tiled_topo_missing_recv_behavior_DI_DISPLAYID_TILED_TOPO_MISSING_RECV_TILE_ONLY,
292}
293
294#[derive(Debug, Clone, Copy, PartialEq, Eq, FFIFrom)]
297#[ffi(ffi::displayid::di_displayid_tiled_topo_single_recv_behavior)]
298#[repr(u32)]
299pub enum TiledTopoSingleRecvBehavior {
300 Undef = ffi::displayid::di_displayid_tiled_topo_single_recv_behavior_DI_DISPLAYID_TILED_TOPO_SINGLE_RECV_UNDEF,
301 TileOnly = ffi::displayid::di_displayid_tiled_topo_single_recv_behavior_DI_DISPLAYID_TILED_TOPO_SINGLE_RECV_TILE_ONLY,
302 Scaled = ffi::displayid::di_displayid_tiled_topo_single_recv_behavior_DI_DISPLAYID_TILED_TOPO_SINGLE_RECV_SCALED,
303 Cloned = ffi::displayid::di_displayid_tiled_topo_single_recv_behavior_DI_DISPLAYID_TILED_TOPO_SINGLE_RECV_CLONED,
304}
305
306#[derive(Debug, Copy, Clone, FFIFrom)]
308#[ffi(ffi::displayid::di_displayid_tiled_topo_caps)]
309pub struct TiledTopoCaps {
310 pub single_enclosure: bool,
311 pub missing_recv_behavior: TiledTopoMissingRecvBehavior,
312 pub single_recv_behavior: TiledTopoSingleRecvBehavior,
313}
314
315#[derive(Debug, Copy, Clone, FFIFrom)]
319#[ffi(ffi::displayid::di_displayid_tiled_topo_bezel)]
320pub struct TiledTopoBezel {
321 pub top_px: f32,
322 pub bottom_px: f32,
323 pub right_px: f32,
324 pub left_px: f32,
325}
326
327#[derive(Debug, Copy, Clone, FFIFrom)]
329#[ffi(ffi::displayid::di_displayid_tiled_topo)]
330pub struct TiledTopo {
331 #[ptr_deref]
332 pub caps: Option<TiledTopoCaps>,
333 pub total_horiz_tiles: i32,
334 pub total_vert_tiles: i32,
335 pub horiz_tile_location: i32,
336 pub vert_tile_location: i32,
337 pub horiz_tile_pixels: i32,
338 pub vert_tile_lines: i32,
339 #[ptr_deref]
340 pub bezel: Option<TiledTopoBezel>,
341 #[cast_as(u8)]
342 pub vendor_id: [char; 3usize],
343 pub product_code: u16,
344 pub serial_number: u32,
345}