EDID.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /*
  2. * Copyright (c) 2022, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/ByteBuffer.h>
  8. #include <AK/ByteReader.h>
  9. #include <AK/Concepts.h>
  10. #include <AK/Endian.h>
  11. #include <AK/Error.h>
  12. #include <AK/FixedPoint.h>
  13. #include <AK/Forward.h>
  14. #include <AK/Span.h>
  15. #include <AK/Vector.h>
  16. #include <LibEDID/DMT.h>
  17. #include <LibEDID/Definitions.h>
  18. #include <LibEDID/VIC.h>
  19. #ifdef KERNEL
  20. # include <Kernel/Library/KString.h>
  21. #else
  22. # include <AK/ByteString.h>
  23. #endif
  24. namespace EDID {
  25. namespace Definitions {
  26. struct EDID;
  27. struct DetailedTiming;
  28. struct DisplayDescriptor;
  29. struct ExtensionBlock;
  30. }
  31. class Parser final {
  32. friend class CEA861ExtensionBlock;
  33. public:
  34. static constexpr size_t BufferSize = 128;
  35. using RawBytes = unsigned char[BufferSize];
  36. protected:
  37. class DisplayFeatures {
  38. public:
  39. bool supports_standby() const { return (m_features & (1 << 7)) != 0; }
  40. bool supports_suspend() const { return (m_features & (1 << 6)) != 0; }
  41. bool supports_off() const { return (m_features & (1 << 5)) != 0; }
  42. bool preferred_timing_mode_includes_pixel_format_and_refresh_rate() const
  43. {
  44. if (m_edid_revision < 4)
  45. return true; // Bit 1 must be set to 1
  46. return (m_features & (1 << 1)) != 0;
  47. }
  48. bool srgb_is_default_color_space() const { return (m_features & (1 << 2)) != 0; }
  49. enum class Frequency : u8 {
  50. Continuous,
  51. NonContinuous,
  52. DefaultGTF,
  53. VESA_DMT
  54. };
  55. Frequency frequency() const
  56. {
  57. if (m_edid_revision < 4)
  58. return ((m_features & 1) != 0) ? Frequency::DefaultGTF : Frequency::VESA_DMT;
  59. return ((m_features & 1) != 0) ? Frequency::Continuous : Frequency::NonContinuous;
  60. }
  61. protected:
  62. DisplayFeatures(u8 features, u8 edid_revision)
  63. : m_features(features)
  64. , m_edid_revision(edid_revision)
  65. {
  66. }
  67. u8 m_features { 0 };
  68. u8 m_edid_revision { 0 };
  69. };
  70. public:
  71. static ErrorOr<Parser> from_bytes(ReadonlyBytes);
  72. static ErrorOr<Parser> from_bytes(ByteBuffer&&);
  73. #ifndef KERNEL
  74. static ErrorOr<Parser> from_display_connector_device(int);
  75. static ErrorOr<Parser> from_display_connector_device(ByteString const&);
  76. #endif
  77. StringView legacy_manufacturer_id() const;
  78. #ifndef KERNEL
  79. ByteString manufacturer_name() const;
  80. #endif
  81. u16 product_code() const;
  82. u32 serial_number() const;
  83. class DigitalDisplayFeatures final : public DisplayFeatures {
  84. friend class Parser;
  85. public:
  86. enum class SupportedColorEncodings : u8 {
  87. RGB444,
  88. RGB444_YCrCb444,
  89. RGB444_YCrCb422,
  90. RGB444_YCrCb444_YCrCb422
  91. };
  92. SupportedColorEncodings supported_color_encodings() const { return (SupportedColorEncodings)((m_features >> 3) & 3); }
  93. private:
  94. DigitalDisplayFeatures(u8 features, u8 edid_revision)
  95. : DisplayFeatures(features, edid_revision)
  96. {
  97. }
  98. };
  99. class AnalogDisplayFeatures final : public DisplayFeatures {
  100. friend class Parser;
  101. public:
  102. enum class DisplayColorType : u8 {
  103. MonochromeOrGrayscale,
  104. RGB,
  105. NonRGB,
  106. Undefined
  107. };
  108. DisplayColorType display_color_type() const { return (DisplayColorType)((m_features >> 3) & 3); }
  109. private:
  110. AnalogDisplayFeatures(u8 features, u8 edid_revision)
  111. : DisplayFeatures(features, edid_revision)
  112. {
  113. }
  114. };
  115. class DigitalDisplay final {
  116. friend class Parser;
  117. public:
  118. enum class ColorBitDepth : u8 {
  119. Undefined = 0,
  120. BPP_6,
  121. BPP_8,
  122. BPP_10,
  123. BPP_12,
  124. BPP_14,
  125. BPP_16,
  126. Reserved
  127. };
  128. enum class SupportedInterface : u8 {
  129. Undefined = 0,
  130. DVI,
  131. HDMI_A,
  132. HDMI_B,
  133. MDDI,
  134. DisplayPort,
  135. Reserved
  136. };
  137. ColorBitDepth color_bit_depth() const { return (ColorBitDepth)((m_video_input_definition >> 4) & 7); }
  138. SupportedInterface supported_interface() const { return ((m_video_input_definition & 0xf) <= 5) ? (SupportedInterface)(m_video_input_definition & 0xf) : SupportedInterface::Reserved; }
  139. DigitalDisplayFeatures const& features() { return m_features; }
  140. private:
  141. DigitalDisplay(u8 video_input_definition, u8 features, u8 edid_revision)
  142. : m_video_input_definition(video_input_definition)
  143. , m_features(features, edid_revision)
  144. {
  145. }
  146. u8 m_video_input_definition { 0 };
  147. DigitalDisplayFeatures m_features;
  148. };
  149. Optional<DigitalDisplay> digital_display() const;
  150. class AnalogDisplay final {
  151. friend class Parser;
  152. public:
  153. bool separate_sync_h_and_v_supported() const { return (m_video_input_definition & (1 << 3)) != 0; }
  154. private:
  155. AnalogDisplay(u8 video_input_definition, u8 features, u8 edid_revision)
  156. : m_video_input_definition(video_input_definition)
  157. , m_features(features, edid_revision)
  158. {
  159. }
  160. u8 m_video_input_definition { 0 };
  161. AnalogDisplayFeatures m_features;
  162. };
  163. Optional<AnalogDisplay> analog_display() const;
  164. class ScreenSize final {
  165. friend class Parser;
  166. public:
  167. unsigned horizontal_cm() const { return m_horizontal_cm; }
  168. unsigned vertical_cm() const { return m_vertical_cm; }
  169. private:
  170. ScreenSize(u8 horizontal_cm, u8 vertical_cm)
  171. : m_horizontal_cm(horizontal_cm)
  172. , m_vertical_cm(vertical_cm)
  173. {
  174. }
  175. u8 m_horizontal_cm { 0 };
  176. u8 m_vertical_cm { 0 };
  177. };
  178. Optional<ScreenSize> screen_size() const;
  179. class ScreenAspectRatio final {
  180. friend class Parser;
  181. public:
  182. enum class Orientation {
  183. Landscape,
  184. Portrait
  185. };
  186. Orientation orientation() const { return m_orientation; }
  187. auto ratio() const { return m_ratio; }
  188. private:
  189. ScreenAspectRatio(Orientation orientation, FixedPoint<16> ratio)
  190. : m_orientation(orientation)
  191. , m_ratio(ratio)
  192. {
  193. }
  194. Orientation m_orientation { Orientation::Landscape };
  195. FixedPoint<16> m_ratio {};
  196. };
  197. Optional<ScreenAspectRatio> aspect_ratio() const;
  198. Optional<FixedPoint<16>> gamma() const;
  199. class EstablishedTiming final {
  200. friend class Parser;
  201. public:
  202. enum class Source {
  203. IBM,
  204. Apple,
  205. VESA,
  206. Manufacturer
  207. };
  208. ALWAYS_INLINE Source source() const { return m_source; }
  209. ALWAYS_INLINE unsigned width() const { return m_width; }
  210. ALWAYS_INLINE unsigned height() const { return m_height; }
  211. ALWAYS_INLINE unsigned refresh_rate() const
  212. {
  213. if (m_source == Source::Manufacturer)
  214. return 0;
  215. return m_refresh_rate_or_manufacturer_specific;
  216. }
  217. ALWAYS_INLINE u8 manufacturer_specific() const
  218. {
  219. VERIFY(m_source == Source::Manufacturer);
  220. return m_refresh_rate_or_manufacturer_specific;
  221. }
  222. ALWAYS_INLINE u8 dmt_id() const { return m_dmt_id; }
  223. private:
  224. constexpr EstablishedTiming(Source source, u16 width, u16 height, u8 refresh_rate_or_manufacturer_specific, u8 dmt_id = 0)
  225. : m_source(source)
  226. , m_width(width)
  227. , m_height(height)
  228. , m_refresh_rate_or_manufacturer_specific(refresh_rate_or_manufacturer_specific)
  229. , m_dmt_id(dmt_id)
  230. {
  231. }
  232. Source m_source { Source::IBM };
  233. u16 m_width { 0 };
  234. u16 m_height { 0 };
  235. u8 m_refresh_rate_or_manufacturer_specific { 0 };
  236. u8 m_dmt_id { 0 };
  237. };
  238. ErrorOr<IterationDecision> for_each_established_timing(Function<IterationDecision(EstablishedTiming const&)>) const;
  239. class StandardTiming final {
  240. friend class Parser;
  241. public:
  242. enum class AspectRatio {
  243. AR_16_10,
  244. AR_4_3,
  245. AR_5_4,
  246. AR_16_9
  247. };
  248. unsigned width() const { return m_width; }
  249. unsigned height() const { return m_height; }
  250. unsigned refresh_rate() const { return m_refresh_rate; }
  251. AspectRatio aspect_ratio() const { return m_aspect_ratio; }
  252. u8 dmt_id() const { return m_dmt_id; }
  253. private:
  254. constexpr StandardTiming(u16 width, u16 height, u8 refresh_rate, AspectRatio aspect_ratio, u8 dmt_id)
  255. : m_width(width)
  256. , m_height(height)
  257. , m_refresh_rate(refresh_rate)
  258. , m_aspect_ratio(aspect_ratio)
  259. , m_dmt_id(dmt_id)
  260. {
  261. }
  262. u16 m_width { 0 };
  263. u16 m_height { 0 };
  264. u8 m_refresh_rate { 0 };
  265. AspectRatio m_aspect_ratio { AspectRatio::AR_16_10 };
  266. u8 m_dmt_id { 0 };
  267. };
  268. ErrorOr<IterationDecision> for_each_standard_timing(Function<IterationDecision(StandardTiming const&)>) const;
  269. class DetailedTiming final {
  270. friend class Parser;
  271. friend class CEA861ExtensionBlock;
  272. public:
  273. u32 pixel_clock_khz() const;
  274. u16 horizontal_addressable_pixels() const;
  275. u16 horizontal_blanking_pixels() const;
  276. u16 vertical_addressable_lines() const;
  277. u16 vertical_blanking_lines() const;
  278. u16 horizontal_front_porch_pixels() const;
  279. ALWAYS_INLINE u16 horizontal_back_porch_pixels() const { return horizontal_blanking_pixels() - horizontal_sync_pulse_width_pixels() - horizontal_front_porch_pixels(); }
  280. u16 horizontal_sync_pulse_width_pixels() const;
  281. u16 vertical_front_porch_lines() const;
  282. ALWAYS_INLINE u16 vertical_back_porch_lines() const { return vertical_blanking_lines() - vertical_sync_pulse_width_lines() - vertical_front_porch_lines(); }
  283. u16 vertical_sync_pulse_width_lines() const;
  284. u16 horizontal_image_size_mm() const;
  285. u16 vertical_image_size_mm() const;
  286. u8 horizontal_right_or_left_border_pixels() const;
  287. u8 vertical_top_or_bottom_border_lines() const;
  288. bool is_interlaced() const;
  289. FixedPoint<16, u32> refresh_rate() const;
  290. private:
  291. DetailedTiming(Parser const& edid, Definitions::DetailedTiming const* detailed_timings)
  292. : m_edid(edid)
  293. , m_detailed_timings(*detailed_timings)
  294. {
  295. }
  296. u16 vertical_addressable_lines_raw() const;
  297. Parser const& m_edid;
  298. Definitions::DetailedTiming const& m_detailed_timings;
  299. };
  300. ErrorOr<IterationDecision> for_each_detailed_timing(Function<IterationDecision(DetailedTiming const&, unsigned)>) const;
  301. Optional<DetailedTiming> detailed_timing(size_t) const;
  302. #ifndef KERNEL
  303. ByteString display_product_name() const;
  304. ByteString display_product_serial_number() const;
  305. #endif
  306. ErrorOr<IterationDecision> for_each_short_video_descriptor(Function<IterationDecision(unsigned, bool, VIC::Details const&)>) const;
  307. class CoordinatedVideoTiming final {
  308. friend class Parser;
  309. public:
  310. enum class AspectRatio : u8 {
  311. AR_4_3 = 0,
  312. AR_16_9 = 1,
  313. AR_16_10 = 2,
  314. AR_15_9 = 3
  315. };
  316. u16 horizontal_addressable_pixels() const;
  317. u16 vertical_addressable_lines() const;
  318. AspectRatio aspect_ratio() const;
  319. u16 preferred_refresh_rate();
  320. ALWAYS_INLINE DMT::CVT cvt_code() const { return m_cvt; }
  321. private:
  322. CoordinatedVideoTiming(DMT::CVT const& cvt)
  323. : m_cvt(cvt)
  324. {
  325. }
  326. DMT::CVT m_cvt;
  327. };
  328. ErrorOr<IterationDecision> for_each_coordinated_video_timing(Function<IterationDecision(CoordinatedVideoTiming const&)>) const;
  329. ErrorOr<IterationDecision> for_each_extension_block(Function<IterationDecision(unsigned, u8, u8, ReadonlyBytes)>) const;
  330. struct SupportedResolution {
  331. unsigned width { 0 };
  332. unsigned height { 0 };
  333. struct RefreshRate {
  334. FixedPoint<16, u32> rate;
  335. bool preferred { false };
  336. bool operator<(RefreshRate const& rhs) const { return rate < rhs.rate; }
  337. };
  338. Vector<RefreshRate, 4> refresh_rates;
  339. };
  340. ErrorOr<Vector<SupportedResolution>> supported_resolutions() const;
  341. Parser() = default;
  342. Parser(Parser&&) = default;
  343. Parser(Parser const&);
  344. Parser& operator=(Parser&&);
  345. Parser& operator=(Parser const&);
  346. bool operator==(Parser const& other) const;
  347. StringView version() const;
  348. auto bytes() const { return m_bytes; }
  349. private:
  350. Parser(ReadonlyBytes);
  351. Parser(ByteBuffer&&);
  352. ErrorOr<void> parse();
  353. template<typename T>
  354. T read_host(T const*) const;
  355. template<Integral T>
  356. requires(sizeof(T) > 1)
  357. T read_le(T const*) const;
  358. template<Integral T>
  359. requires(sizeof(T) > 1)
  360. T read_be(T const*) const;
  361. Definitions::EDID const& raw_edid() const;
  362. ErrorOr<IterationDecision> for_each_display_descriptor(Function<IterationDecision(u8, Definitions::DisplayDescriptor const&)>) const;
  363. ByteBuffer m_bytes_buffer;
  364. ReadonlyBytes m_bytes;
  365. u8 m_revision { 0 };
  366. #ifdef KERNEL
  367. OwnPtr<Kernel::KString> m_version;
  368. #else
  369. ByteString m_version;
  370. #endif
  371. char m_legacy_manufacturer_id[4] {};
  372. bool m_legacy_manufacturer_id_valid { false };
  373. };
  374. }