mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-10 13:00:29 +03:00
8184870f93
This library can be used (for the most part) by kernel drivers as well as user mode. For this reason FixedPoint is used rather than floating point, but kept to a minimum.
409 lines
20 KiB
C++
409 lines
20 KiB
C++
/*
|
|
* Copyright (c) 2022, the SerenityOS developers.
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibEDID/DMT.h>
|
|
#include <LibEDID/EDID.h>
|
|
#include <LibTest/TestCase.h>
|
|
|
|
static const u8 edid1_bin[] = {
|
|
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x49, 0x14, 0x34, 0x12,
|
|
0x00, 0x00, 0x00, 0x00, 0x2a, 0x18, 0x01, 0x04, 0xa5, 0x1a, 0x13, 0x78,
|
|
0x06, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x21,
|
|
0x08, 0x00, 0xe1, 0xc0, 0xd1, 0xc0, 0xd1, 0x00, 0xa9, 0x40, 0xb3, 0x00,
|
|
0x95, 0x00, 0x81, 0x80, 0x81, 0x40, 0x25, 0x20, 0x00, 0x66, 0x41, 0x00,
|
|
0x1a, 0x30, 0x00, 0x1e, 0x33, 0x40, 0x04, 0xc3, 0x10, 0x00, 0x00, 0x18,
|
|
0x00, 0x00, 0x00, 0xfd, 0x00, 0x32, 0x7d, 0x1e, 0xa0, 0x78, 0x01, 0x0a,
|
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x51,
|
|
0x45, 0x4d, 0x55, 0x20, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x0a,
|
|
0x00, 0x00, 0x00, 0xf7, 0x00, 0x0a, 0x00, 0x40, 0x82, 0x00, 0x28, 0x20,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x02, 0x03, 0x0a, 0x00,
|
|
0x45, 0x7d, 0x65, 0x60, 0x59, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0xf2
|
|
};
|
|
|
|
TEST_CASE(edid1)
|
|
{
|
|
auto edid_load_result = EDID::Parser::from_bytes({ edid1_bin, sizeof(edid1_bin) });
|
|
EXPECT(!edid_load_result.is_error());
|
|
auto edid = edid_load_result.release_value();
|
|
EXPECT(edid.legacy_manufacturer_id() == "RHT");
|
|
EXPECT(!edid.aspect_ratio().has_value());
|
|
auto screen_size = edid.screen_size();
|
|
EXPECT(screen_size.has_value());
|
|
EXPECT(screen_size.value().horizontal_cm() == 26);
|
|
EXPECT(screen_size.value().vertical_cm() == 19);
|
|
auto gamma = edid.gamma();
|
|
EXPECT(gamma.has_value());
|
|
EXPECT(gamma.value() >= 2.19f && gamma.value() <= 2.21f);
|
|
EXPECT(edid.display_product_name() == "QEMU Monitor");
|
|
|
|
{
|
|
static constexpr struct {
|
|
unsigned width;
|
|
unsigned height;
|
|
unsigned refresh_rate;
|
|
EDID::Parser::EstablishedTiming::Source source;
|
|
u8 dmt_id { 0 };
|
|
} expected_established_timings[] = {
|
|
{ 640, 480, 60, EDID::Parser::EstablishedTiming::Source::IBM, 0x4 },
|
|
{ 800, 600, 60, EDID::Parser::EstablishedTiming::Source::VESA, 0x9 },
|
|
{ 1024, 768, 60, EDID::Parser::EstablishedTiming::Source::VESA, 0x10 },
|
|
{ 1280, 768, 60, EDID::Parser::EstablishedTiming::Source::VESA, 0x17 },
|
|
{ 1360, 768, 60, EDID::Parser::EstablishedTiming::Source::VESA, 0x27 },
|
|
{ 1400, 1050, 60, EDID::Parser::EstablishedTiming::Source::VESA, 0x2a },
|
|
{ 1792, 1344, 60, EDID::Parser::EstablishedTiming::Source::VESA, 0x3e },
|
|
{ 1856, 1392, 60, EDID::Parser::EstablishedTiming::Source::VESA, 0x41 },
|
|
{ 1920, 1440, 60, EDID::Parser::EstablishedTiming::Source::VESA, 0x49 }
|
|
};
|
|
static constexpr size_t expected_established_timings_count = sizeof(expected_established_timings) / sizeof(expected_established_timings[0]);
|
|
size_t established_timings_found = 0;
|
|
auto result = edid.for_each_established_timing([&](auto& established_timings) {
|
|
EXPECT(established_timings_found < expected_established_timings_count);
|
|
auto& expected_timings = expected_established_timings[established_timings_found];
|
|
EXPECT(established_timings.width() == expected_timings.width);
|
|
EXPECT(established_timings.height() == expected_timings.height);
|
|
EXPECT(established_timings.refresh_rate() == expected_timings.refresh_rate);
|
|
EXPECT(established_timings.source() == expected_timings.source);
|
|
EXPECT(established_timings.dmt_id() == expected_timings.dmt_id);
|
|
established_timings_found++;
|
|
return IterationDecision::Continue;
|
|
});
|
|
EXPECT(!result.is_error());
|
|
EXPECT(result.value() == IterationDecision::Continue);
|
|
EXPECT(established_timings_found == expected_established_timings_count);
|
|
}
|
|
|
|
{
|
|
static constexpr struct {
|
|
unsigned width;
|
|
unsigned height;
|
|
unsigned refresh_rate;
|
|
u8 dmt_id { 0 };
|
|
} expected_standard_established_timings[] = {
|
|
{ 2048, 1152, 60, 0x54 },
|
|
{ 1920, 1080, 60, 0x52 },
|
|
{ 1920, 1200, 60, 0x45 },
|
|
{ 1600, 1200, 60, 0x33 },
|
|
{ 1680, 1050, 60, 0x3a },
|
|
{ 1440, 900, 60, 0x2f },
|
|
{ 1280, 1024, 60, 0x23 },
|
|
{ 1280, 960, 60, 0x20 }
|
|
};
|
|
static constexpr size_t expected_standard_timings_count = sizeof(expected_standard_established_timings) / sizeof(expected_standard_established_timings[0]);
|
|
size_t standard_timings_found = 0;
|
|
auto result = edid.for_each_standard_timing([&](auto& standard_timings) {
|
|
EXPECT(standard_timings_found < expected_standard_timings_count);
|
|
auto& expected_timings = expected_standard_established_timings[standard_timings_found];
|
|
EXPECT(standard_timings.dmt_id() == expected_timings.dmt_id);
|
|
EXPECT(standard_timings.width() == expected_timings.width);
|
|
EXPECT(standard_timings.height() == expected_timings.height);
|
|
EXPECT(standard_timings.refresh_rate() == expected_timings.refresh_rate);
|
|
standard_timings_found++;
|
|
return IterationDecision::Continue;
|
|
});
|
|
EXPECT(!result.is_error());
|
|
EXPECT(result.value() == IterationDecision::Continue);
|
|
EXPECT(standard_timings_found == expected_standard_timings_count);
|
|
}
|
|
|
|
{
|
|
static constexpr struct {
|
|
unsigned block_id;
|
|
unsigned width;
|
|
unsigned height;
|
|
unsigned refresh_rate;
|
|
} expected_detailed_timings[] = {
|
|
{ 0, 1024, 768, 75 }
|
|
};
|
|
static constexpr size_t expected_detailed_timings_count = sizeof(expected_detailed_timings) / sizeof(expected_detailed_timings[0]);
|
|
size_t detailed_timings_found = 0;
|
|
auto result = edid.for_each_detailed_timing([&](auto& detailed_timing, unsigned block_id) {
|
|
EXPECT(detailed_timings_found < expected_detailed_timings_count);
|
|
auto& expected_timings = expected_detailed_timings[detailed_timings_found];
|
|
EXPECT(block_id == expected_timings.block_id);
|
|
EXPECT(detailed_timing.horizontal_addressable_pixels() == expected_timings.width);
|
|
EXPECT(detailed_timing.vertical_addressable_lines() == expected_timings.height);
|
|
EXPECT(detailed_timing.refresh_rate().lround() == expected_timings.refresh_rate);
|
|
detailed_timings_found++;
|
|
return IterationDecision::Continue;
|
|
});
|
|
EXPECT(!result.is_error());
|
|
EXPECT(result.value() == IterationDecision::Continue);
|
|
EXPECT(detailed_timings_found == expected_detailed_timings_count);
|
|
}
|
|
|
|
{
|
|
static constexpr u8 expected_vic_ids[] = { 125, 101, 96, 89, 31 };
|
|
static constexpr size_t expected_vic_ids_count = sizeof(expected_vic_ids) / sizeof(expected_vic_ids[0]);
|
|
size_t vic_ids_found = 0;
|
|
auto result = edid.for_each_short_video_descriptor([&](unsigned block_id, bool is_native, EDID::VIC::Details const& vic) {
|
|
EXPECT(vic_ids_found < expected_vic_ids_count);
|
|
EXPECT(block_id == 1);
|
|
EXPECT(!is_native); // none are marked as native
|
|
EXPECT(vic.vic_id == expected_vic_ids[vic_ids_found]);
|
|
vic_ids_found++;
|
|
return IterationDecision::Continue;
|
|
});
|
|
EXPECT(!result.is_error());
|
|
EXPECT(result.value() == IterationDecision::Continue);
|
|
EXPECT(vic_ids_found == expected_vic_ids_count);
|
|
}
|
|
|
|
{
|
|
// This edid has one CEA861 extension block only
|
|
size_t extension_blocks_found = 0;
|
|
auto result = edid.for_each_extension_block([&](unsigned block_id, u8 tag, u8 revision, ReadonlyBytes) {
|
|
EXPECT(block_id == 1);
|
|
EXPECT(tag == 0x2);
|
|
EXPECT(revision == 3);
|
|
extension_blocks_found++;
|
|
return IterationDecision::Continue;
|
|
});
|
|
EXPECT(!result.is_error());
|
|
EXPECT(result.value() == IterationDecision::Continue);
|
|
EXPECT(extension_blocks_found == 1);
|
|
}
|
|
}
|
|
|
|
static const u8 edid2_bin[] = {
|
|
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x72, 0x1d, 0x08,
|
|
0xd2, 0x02, 0x96, 0x49, 0x20, 0x1e, 0x01, 0x04, 0xb5, 0x3c, 0x22, 0x78,
|
|
0x3b, 0xff, 0x15, 0xa6, 0x53, 0x4a, 0x98, 0x26, 0x0f, 0x50, 0x54, 0xbf,
|
|
0xef, 0x80, 0xd1, 0xc0, 0xb3, 0x00, 0x95, 0x00, 0x81, 0x80, 0x81, 0x40,
|
|
0x81, 0xc0, 0x01, 0x01, 0x01, 0x01, 0x86, 0x6f, 0x00, 0x3c, 0xa0, 0xa0,
|
|
0x0f, 0x50, 0x08, 0x20, 0x35, 0x00, 0x55, 0x50, 0x21, 0x00, 0x00, 0x1e,
|
|
0x56, 0x5e, 0x00, 0xa0, 0xa0, 0xa0, 0x29, 0x50, 0x30, 0x20, 0x35, 0x00,
|
|
0x55, 0x50, 0x21, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x30,
|
|
0x4b, 0x78, 0x78, 0x1e, 0x01, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
|
0x00, 0x00, 0x00, 0xfc, 0x00, 0x43, 0x42, 0x32, 0x37, 0x32, 0x55, 0x0a,
|
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xc5, 0x02, 0x03, 0x33, 0x71,
|
|
0x4c, 0x12, 0x13, 0x04, 0x1f, 0x90, 0x14, 0x05, 0x01, 0x11, 0x02, 0x03,
|
|
0x4a, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0xe2, 0x00, 0xc0,
|
|
0x67, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x38, 0x3c, 0xe3, 0x05, 0xe3, 0x01,
|
|
0xe3, 0x0f, 0x00, 0x00, 0xe6, 0x06, 0x07, 0x01, 0x60, 0x60, 0x45, 0x01,
|
|
0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00, 0x55,
|
|
0x50, 0x21, 0x00, 0x00, 0x1e, 0x01, 0x1d, 0x00, 0xbc, 0x52, 0xd0, 0x1e,
|
|
0x20, 0xb8, 0x28, 0x55, 0x40, 0x55, 0x50, 0x21, 0x00, 0x00, 0x1e, 0x56,
|
|
0x5e, 0x00, 0xa0, 0xa0, 0xa0, 0x29, 0x50, 0x30, 0x20, 0x35, 0x00, 0x55,
|
|
0x50, 0x21, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0xe1
|
|
};
|
|
|
|
TEST_CASE(edid2)
|
|
{
|
|
auto edid_load_result = EDID::Parser::from_bytes({ edid2_bin, sizeof(edid2_bin) });
|
|
EXPECT(!edid_load_result.is_error());
|
|
auto edid = edid_load_result.release_value();
|
|
EXPECT(edid.legacy_manufacturer_id() == "ACR");
|
|
EXPECT(edid.serial_number() == 1234567890);
|
|
auto digital_interface = edid.digital_display();
|
|
EXPECT(digital_interface.has_value());
|
|
EXPECT(digital_interface.value().color_bit_depth() == EDID::Parser::DigitalDisplay::ColorBitDepth::BPP_10);
|
|
EXPECT(digital_interface.value().supported_interface() == EDID::Parser::DigitalDisplay::SupportedInterface::DisplayPort);
|
|
EXPECT(!digital_interface.value().features().supports_standby());
|
|
EXPECT(!digital_interface.value().features().supports_suspend());
|
|
EXPECT(digital_interface.value().features().supports_off());
|
|
EXPECT(digital_interface.value().features().preferred_timing_mode_includes_pixel_format_and_refresh_rate());
|
|
EXPECT(!digital_interface.value().features().srgb_is_default_color_space());
|
|
EXPECT(digital_interface.value().features().frequency() == EDID::Parser::DigitalDisplayFeatures::Frequency::Continuous);
|
|
EXPECT(digital_interface.value().features().supported_color_encodings() == EDID::Parser::DigitalDisplayFeatures::SupportedColorEncodings::RGB444_YCrCb444_YCrCb422);
|
|
EXPECT(!edid.aspect_ratio().has_value());
|
|
auto screen_size = edid.screen_size();
|
|
EXPECT(screen_size.has_value());
|
|
EXPECT(screen_size.value().horizontal_cm() == 60);
|
|
EXPECT(screen_size.value().vertical_cm() == 34);
|
|
auto gamma = edid.gamma();
|
|
EXPECT(gamma.has_value());
|
|
EXPECT(gamma.value() >= 2.19f && gamma.value() <= 2.21f);
|
|
EXPECT(edid.display_product_name() == "CB272U");
|
|
|
|
{
|
|
static constexpr struct {
|
|
unsigned width;
|
|
unsigned height;
|
|
unsigned refresh_rate;
|
|
EDID::Parser::EstablishedTiming::Source source;
|
|
u8 dmt_id { 0 };
|
|
} expected_established_timings[] = {
|
|
{ 720, 400, 70, EDID::Parser::EstablishedTiming::Source::IBM },
|
|
{ 640, 480, 60, EDID::Parser::EstablishedTiming::Source::IBM, 0x4 },
|
|
{ 640, 480, 67, EDID::Parser::EstablishedTiming::Source::Apple },
|
|
{ 640, 480, 73, EDID::Parser::EstablishedTiming::Source::VESA, 0x5 },
|
|
{ 640, 480, 75, EDID::Parser::EstablishedTiming::Source::VESA, 0x6 },
|
|
{ 800, 600, 56, EDID::Parser::EstablishedTiming::Source::VESA, 0x8 },
|
|
{ 800, 600, 60, EDID::Parser::EstablishedTiming::Source::VESA, 0x9 },
|
|
{ 800, 600, 72, EDID::Parser::EstablishedTiming::Source::VESA, 0xa },
|
|
{ 800, 600, 75, EDID::Parser::EstablishedTiming::Source::VESA, 0xb },
|
|
{ 832, 624, 75, EDID::Parser::EstablishedTiming::Source::Apple },
|
|
{ 1024, 768, 60, EDID::Parser::EstablishedTiming::Source::VESA, 0x10 },
|
|
{ 1024, 768, 70, EDID::Parser::EstablishedTiming::Source::VESA, 0x11 },
|
|
{ 1024, 768, 75, EDID::Parser::EstablishedTiming::Source::VESA, 0x12 },
|
|
{ 1280, 1024, 75, EDID::Parser::EstablishedTiming::Source::VESA, 0x24 },
|
|
{ 1152, 870, 75, EDID::Parser::EstablishedTiming::Source::Apple }
|
|
};
|
|
static constexpr size_t expected_established_timings_count = sizeof(expected_established_timings) / sizeof(expected_established_timings[0]);
|
|
size_t established_timings_found = 0;
|
|
auto result = edid.for_each_established_timing([&](auto& established_timings) {
|
|
EXPECT(established_timings_found < expected_established_timings_count);
|
|
auto& expected_timings = expected_established_timings[established_timings_found];
|
|
EXPECT(established_timings.width() == expected_timings.width);
|
|
EXPECT(established_timings.height() == expected_timings.height);
|
|
EXPECT(established_timings.refresh_rate() == expected_timings.refresh_rate);
|
|
EXPECT(established_timings.source() == expected_timings.source);
|
|
EXPECT(established_timings.dmt_id() == expected_timings.dmt_id);
|
|
established_timings_found++;
|
|
return IterationDecision::Continue;
|
|
});
|
|
EXPECT(!result.is_error());
|
|
EXPECT(result.value() == IterationDecision::Continue);
|
|
EXPECT(established_timings_found == expected_established_timings_count);
|
|
}
|
|
|
|
{
|
|
static constexpr struct {
|
|
unsigned width;
|
|
unsigned height;
|
|
unsigned refresh_rate;
|
|
u8 dmt_id { 0 };
|
|
} expected_standard_established_timings[] = {
|
|
{ 1920, 1080, 60, 0x52 },
|
|
{ 1680, 1050, 60, 0x3a },
|
|
{ 1440, 900, 60, 0x2f },
|
|
{ 1280, 1024, 60, 0x23 },
|
|
{ 1280, 960, 60, 0x20 },
|
|
{ 1280, 720, 60, 0x55 },
|
|
};
|
|
static constexpr size_t expected_standard_timings_count = sizeof(expected_standard_established_timings) / sizeof(expected_standard_established_timings[0]);
|
|
size_t standard_timings_found = 0;
|
|
auto result = edid.for_each_standard_timing([&](auto& standard_timings) {
|
|
EXPECT(standard_timings_found < expected_standard_timings_count);
|
|
auto& expected_timings = expected_standard_established_timings[standard_timings_found];
|
|
EXPECT(standard_timings.dmt_id() == expected_timings.dmt_id);
|
|
EXPECT(standard_timings.width() == expected_timings.width);
|
|
EXPECT(standard_timings.height() == expected_timings.height);
|
|
EXPECT(standard_timings.refresh_rate() == expected_timings.refresh_rate);
|
|
standard_timings_found++;
|
|
return IterationDecision::Continue;
|
|
});
|
|
EXPECT(!result.is_error());
|
|
EXPECT(result.value() == IterationDecision::Continue);
|
|
EXPECT(standard_timings_found == expected_standard_timings_count);
|
|
}
|
|
|
|
{
|
|
static constexpr struct {
|
|
unsigned block_id;
|
|
unsigned width;
|
|
unsigned height;
|
|
unsigned refresh_rate;
|
|
} expected_detailed_timings[] = {
|
|
{ 0, 2560, 1440, 75 },
|
|
{ 0, 2560, 1440, 60 },
|
|
{ 1, 1280, 720, 60 },
|
|
{ 1, 1280, 720, 50 },
|
|
{ 1, 2560, 1440, 60 }
|
|
};
|
|
static constexpr size_t expected_detailed_timings_count = sizeof(expected_detailed_timings) / sizeof(expected_detailed_timings[0]);
|
|
size_t detailed_timings_found = 0;
|
|
auto result = edid.for_each_detailed_timing([&](auto& detailed_timing, unsigned block_id) {
|
|
EXPECT(detailed_timings_found < expected_detailed_timings_count);
|
|
auto& expected_timings = expected_detailed_timings[detailed_timings_found];
|
|
EXPECT(block_id == expected_timings.block_id);
|
|
EXPECT(detailed_timing.horizontal_addressable_pixels() == expected_timings.width);
|
|
EXPECT(detailed_timing.vertical_addressable_lines() == expected_timings.height);
|
|
EXPECT(detailed_timing.refresh_rate().lround() == expected_timings.refresh_rate);
|
|
detailed_timings_found++;
|
|
return IterationDecision::Continue;
|
|
});
|
|
EXPECT(!result.is_error());
|
|
EXPECT(result.value() == IterationDecision::Continue);
|
|
EXPECT(detailed_timings_found == expected_detailed_timings_count);
|
|
}
|
|
|
|
{
|
|
static constexpr u8 expected_vic_ids[] = { 18, 19, 4, 31, 16, 20, 5, 1, 17, 2, 3, 74 };
|
|
static constexpr size_t expected_vic_ids_count = sizeof(expected_vic_ids) / sizeof(expected_vic_ids[0]);
|
|
size_t vic_ids_found = 0;
|
|
auto result = edid.for_each_short_video_descriptor([&](unsigned block_id, bool is_native, EDID::VIC::Details const& vic) {
|
|
EXPECT(vic_ids_found < expected_vic_ids_count);
|
|
EXPECT(block_id == 1);
|
|
EXPECT(is_native == (vic_ids_found == 4)); // the 5th value is marked native
|
|
EXPECT(vic.vic_id == expected_vic_ids[vic_ids_found]);
|
|
vic_ids_found++;
|
|
return IterationDecision::Continue;
|
|
});
|
|
EXPECT(!result.is_error());
|
|
EXPECT(result.value() == IterationDecision::Continue);
|
|
EXPECT(vic_ids_found == expected_vic_ids_count);
|
|
}
|
|
|
|
{
|
|
// This edid has one CEA861 extension block only
|
|
size_t extension_blocks_found = 0;
|
|
auto result = edid.for_each_extension_block([&](unsigned block_id, u8 tag, u8 revision, ReadonlyBytes) {
|
|
EXPECT(block_id == 1);
|
|
EXPECT(tag == 0x2);
|
|
EXPECT(revision == 3);
|
|
extension_blocks_found++;
|
|
return IterationDecision::Continue;
|
|
});
|
|
EXPECT(!result.is_error());
|
|
EXPECT(result.value() == IterationDecision::Continue);
|
|
EXPECT(extension_blocks_found == 1);
|
|
}
|
|
}
|
|
|
|
TEST_CASE(dmt_find_std_id)
|
|
{
|
|
auto* dmt = EDID::DMT::find_timing_by_std_id(0xd1, 0xf);
|
|
EXPECT(dmt);
|
|
EXPECT(dmt->dmt_id == 0x46);
|
|
EXPECT(dmt->horizontal_pixels == 1920 && dmt->vertical_lines == 1200);
|
|
}
|
|
|
|
TEST_CASE(dmt_frequency)
|
|
{
|
|
auto* dmt = EDID::DMT::find_timing_by_dmt_id(0x4);
|
|
EXPECT(dmt);
|
|
static constexpr FixedPoint<16, u32> expected_vertical_frequency(59.940);
|
|
EXPECT(dmt->vertical_frequency_hz() == expected_vertical_frequency);
|
|
static constexpr FixedPoint<16, u32> expected_horizontal_frequency(31.469);
|
|
EXPECT(dmt->horizontal_frequency_khz() == expected_horizontal_frequency);
|
|
}
|
|
|
|
TEST_CASE(vic)
|
|
{
|
|
EXPECT(!EDID::VIC::find_details_by_vic_id(0)); // invalid
|
|
EXPECT(!EDID::VIC::find_details_by_vic_id(160)); // forbidden range
|
|
EXPECT(!EDID::VIC::find_details_by_vic_id(250)); // reserved
|
|
auto* vic_def_32 = EDID::VIC::find_details_by_vic_id(32);
|
|
EXPECT(vic_def_32);
|
|
EXPECT(vic_def_32->vic_id == 32);
|
|
auto* vic_def_200 = EDID::VIC::find_details_by_vic_id(200);
|
|
EXPECT(vic_def_200);
|
|
EXPECT(vic_def_200->vic_id == 200);
|
|
|
|
for (unsigned vic_id = 0; vic_id <= 0xff; vic_id++) {
|
|
auto* vic_def = EDID::VIC::find_details_by_vic_id((u8)vic_id);
|
|
if (vic_def) {
|
|
EXPECT((vic_id >= 1 && vic_id <= 127) || (vic_id >= 193 && vic_id <= 219));
|
|
EXPECT(vic_def->vic_id == vic_id);
|
|
} else {
|
|
EXPECT(vic_id == 0 || (vic_id >= 128 && vic_id <= 192) || (vic_id >= 220));
|
|
}
|
|
}
|
|
}
|