Commit a2b7df9d authored by oshima's avatar oshima Committed by Commit bot

Read EDID for the 1st display for startup

BUG=449662, chrome-os-partner:35334
TEST=covered by unittest. Also tested on link_freon

Review URL: https://codereview.chromium.org/854203002

Cr-Commit-Position: refs/heads/master@{#312947}
parent 3932d125
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/hash.h" #include "base/hash.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/sys_byteorder.h" #include "base/sys_byteorder.h"
#include "ui/gfx/geometry/size.h"
namespace ui { namespace ui {
...@@ -37,7 +38,8 @@ bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid, ...@@ -37,7 +38,8 @@ bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid,
std::string product_name; std::string product_name;
// ParseOutputDeviceData fails if it doesn't have product_name. // ParseOutputDeviceData fails if it doesn't have product_name.
ParseOutputDeviceData(edid, &manufacturer_id, &product_name); ParseOutputDeviceData(edid, &manufacturer_id, &product_name, nullptr,
nullptr);
// Generates product specific value from product_name instead of product code. // Generates product specific value from product_name instead of product code.
// See crbug.com/240341 // See crbug.com/240341
...@@ -55,7 +57,9 @@ bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid, ...@@ -55,7 +57,9 @@ bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid,
bool ParseOutputDeviceData(const std::vector<uint8_t>& edid, bool ParseOutputDeviceData(const std::vector<uint8_t>& edid,
uint16_t* manufacturer_id, uint16_t* manufacturer_id,
std::string* human_readable_name) { std::string* human_readable_name,
gfx::Size* active_pixel_out,
gfx::Size* physical_display_size_out) {
// See http://en.wikipedia.org/wiki/Extended_display_identification_data // See http://en.wikipedia.org/wiki/Extended_display_identification_data
// for the details of EDID data format. We use the following data: // for the details of EDID data format. We use the following data:
// bytes 8-9: manufacturer EISA ID, in big-endian // bytes 8-9: manufacturer EISA ID, in big-endian
...@@ -82,15 +86,57 @@ bool ParseOutputDeviceData(const std::vector<uint8_t>& edid, ...@@ -82,15 +86,57 @@ bool ParseOutputDeviceData(const std::vector<uint8_t>& edid,
#endif #endif
} }
if (!human_readable_name) if (human_readable_name)
return true; human_readable_name->clear();
human_readable_name->clear();
for (unsigned int i = 0; i < kNumDescriptors; ++i) { for (unsigned int i = 0; i < kNumDescriptors; ++i) {
if (edid.size() < kDescriptorOffset + (i + 1) * kDescriptorLength) if (edid.size() < kDescriptorOffset + (i + 1) * kDescriptorLength)
break; break;
size_t offset = kDescriptorOffset + i * kDescriptorLength; size_t offset = kDescriptorOffset + i * kDescriptorLength;
// Detailed Timing Descriptor:
if (edid[offset] != 0 && edid[offset + 1] != 0) {
const int kMaxResolution = 10080; // 8k display.
if (active_pixel_out) {
const int kHorizontalPixelLsbOffset = 2;
const int kHorizontalPixelMsbOffset = 4;
const int kVerticalPixelLsbOffset = 5;
const int kVerticalPixelMsbOffset = 7;
int h_lsb = edid[offset + kHorizontalPixelLsbOffset];
int h_msb = edid[offset + kHorizontalPixelMsbOffset];
int h_pixel = std::min(h_lsb + ((h_msb & 0xF0) << 4), kMaxResolution);
int v_lsb = edid[offset + kVerticalPixelLsbOffset];
int v_msb = edid[offset + kVerticalPixelMsbOffset];
int v_pixel = std::min(v_lsb + ((v_msb & 0xF0) << 4), kMaxResolution);
active_pixel_out->SetSize(h_pixel, v_pixel);
// EDID may contain multiple DTD. Use first one that
// contains the highest resolution.
active_pixel_out = nullptr;
}
if (physical_display_size_out) {
const int kHorizontalSizeLsbOffset = 12;
const int kVerticalSizeLsbOffset = 13;
const int kSizeMsbOffset = 14;
int h_lsb = edid[offset + kHorizontalSizeLsbOffset];
int v_lsb = edid[offset + kVerticalSizeLsbOffset];
int msb = edid[offset + kSizeMsbOffset];
int h_size = h_lsb + ((msb & 0xF0) << 4);
int v_size = v_lsb + ((msb & 0x0F) << 8);
physical_display_size_out->SetSize(h_size, v_size);
physical_display_size_out = nullptr;
}
continue;
}
// EDID Other Monitor Descriptors:
// If the descriptor contains the display name, it has the following // If the descriptor contains the display name, it has the following
// structure: // structure:
// bytes 0-2, 4: \0 // bytes 0-2, 4: \0
...@@ -99,22 +145,26 @@ bool ParseOutputDeviceData(const std::vector<uint8_t>& edid, ...@@ -99,22 +145,26 @@ bool ParseOutputDeviceData(const std::vector<uint8_t>& edid,
// we should check bytes 0-2 and 4, since it may have other values in // we should check bytes 0-2 and 4, since it may have other values in
// case that the descriptor contains other type of data. // case that the descriptor contains other type of data.
if (edid[offset] == 0 && edid[offset + 1] == 0 && edid[offset + 2] == 0 && if (edid[offset] == 0 && edid[offset + 1] == 0 && edid[offset + 2] == 0 &&
edid[offset + 3] == kMonitorNameDescriptor && edid[offset + 4] == 0) { edid[offset + 3] == kMonitorNameDescriptor && edid[offset + 4] == 0 &&
human_readable_name) {
std::string found_name(reinterpret_cast<const char*>(&edid[offset + 5]), std::string found_name(reinterpret_cast<const char*>(&edid[offset + 5]),
kDescriptorLength - 5); kDescriptorLength - 5);
base::TrimWhitespaceASCII( base::TrimWhitespaceASCII(
found_name, base::TRIM_TRAILING, human_readable_name); found_name, base::TRIM_TRAILING, human_readable_name);
break; continue;
} }
} }
// Verify if the |human_readable_name| consists of printable characters only. // Verify if the |human_readable_name| consists of printable characters only.
for (size_t i = 0; i < human_readable_name->size(); ++i) { // TODO(oshima|muka): Consider replacing unprintable chars with white space.
char c = (*human_readable_name)[i]; if (human_readable_name) {
if (!isascii(c) || !isprint(c)) { for (size_t i = 0; i < human_readable_name->size(); ++i) {
human_readable_name->clear(); char c = (*human_readable_name)[i];
LOG(ERROR) << "invalid EDID: human unreadable char in name"; if (!isascii(c) || !isprint(c)) {
return false; human_readable_name->clear();
LOG(ERROR) << "invalid EDID: human unreadable char in name";
return false;
}
} }
} }
......
...@@ -12,6 +12,10 @@ ...@@ -12,6 +12,10 @@
#include "ui/display/util/display_util_export.h" #include "ui/display/util/display_util_export.h"
namespace gfx {
class Size;
}
// EDID (Extended Display Identification Data) is a format for monitor // EDID (Extended Display Identification Data) is a format for monitor
// metadata. This provides a parser for the data. // metadata. This provides a parser for the data.
...@@ -24,14 +28,17 @@ DISPLAY_UTIL_EXPORT bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid, ...@@ -24,14 +28,17 @@ DISPLAY_UTIL_EXPORT bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid,
uint8_t index, uint8_t index,
int64_t* display_id_out); int64_t* display_id_out);
// Parses |edid| as EDID data and stores extracted data into |manufacturer_id| // Parses |edid| as EDID data and stores extracted data into |manufacturer_id|,
// and |human_readable_name| and returns true. NULL can be passed for unwanted // |human_readable_name|, |active_pixel_out| and |physical_display_size_out|,
// output parameters. Some devices (especially internal displays) may not have // then returns true. nullptr can be passed for unwanted output parameters.
// the field for |human_readable_name|, and it will return true in that case. // Some devices (especially internal displays) may not have the field for
// |human_readable_name|, and it will return true in that case.
DISPLAY_UTIL_EXPORT bool ParseOutputDeviceData( DISPLAY_UTIL_EXPORT bool ParseOutputDeviceData(
const std::vector<uint8_t>& edid, const std::vector<uint8_t>& edid,
uint16_t* manufacturer_id, uint16_t* manufacturer_id,
std::string* human_readable_name); std::string* human_readable_name,
gfx::Size* active_pixel_out,
gfx::Size* physical_display_size_out);
DISPLAY_UTIL_EXPORT bool ParseOutputOverscanFlag( DISPLAY_UTIL_EXPORT bool ParseOutputOverscanFlag(
const std::vector<uint8_t>& edid, const std::vector<uint8_t>& edid,
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/size.h"
namespace ui { namespace ui {
...@@ -93,6 +94,11 @@ const unsigned char kLP2565B[] = ...@@ -93,6 +94,11 @@ const unsigned char kLP2565B[] =
"\x50\x20\x4C\x50\x32\x34\x36\x35\x0A\x20\x20\x20\x00\x00\x00\xFF" "\x50\x20\x4C\x50\x32\x34\x36\x35\x0A\x20\x20\x20\x00\x00\x00\xFF"
"\x00\x43\x4E\x4B\x38\x30\x32\x30\x34\x48\x4D\x0A\x20\x20\x00\x45"; "\x00\x43\x4E\x4B\x38\x30\x32\x30\x34\x48\x4D\x0A\x20\x20\x00\x45";
void Reset(gfx::Size* pixel, gfx::Size* size) {
pixel->SetSize(0, 0);
size->SetSize(0, 0);
}
} // namespace } // namespace
TEST(EDIDParserTest, ParseOverscanFlag) { TEST(EDIDParserTest, ParseOverscanFlag) {
...@@ -149,29 +155,42 @@ TEST(EDIDParserTest, ParseEDID) { ...@@ -149,29 +155,42 @@ TEST(EDIDParserTest, ParseEDID) {
std::string human_readable_name; std::string human_readable_name;
std::vector<uint8_t> edid( std::vector<uint8_t> edid(
kNormalDisplay, kNormalDisplay + charsize(kNormalDisplay)); kNormalDisplay, kNormalDisplay + charsize(kNormalDisplay));
EXPECT_TRUE(ParseOutputDeviceData( gfx::Size pixel;
edid, &manufacturer_id, &human_readable_name)); gfx::Size size;
EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id,
&human_readable_name, &pixel, &size));
EXPECT_EQ(0x22f0u, manufacturer_id); EXPECT_EQ(0x22f0u, manufacturer_id);
EXPECT_EQ("HP ZR30w", human_readable_name); EXPECT_EQ("HP ZR30w", human_readable_name);
EXPECT_EQ("2560x1600", pixel.ToString());
EXPECT_EQ("641x400", size.ToString());
manufacturer_id = 0; manufacturer_id = 0;
human_readable_name.clear(); human_readable_name.clear();
Reset(&pixel, &size);
edid.assign(kInternalDisplay, kInternalDisplay + charsize(kInternalDisplay)); edid.assign(kInternalDisplay, kInternalDisplay + charsize(kInternalDisplay));
EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, NULL));
EXPECT_TRUE(
ParseOutputDeviceData(edid, &manufacturer_id, nullptr, &pixel, &size));
EXPECT_EQ(0x4ca3u, manufacturer_id); EXPECT_EQ(0x4ca3u, manufacturer_id);
EXPECT_EQ("", human_readable_name); EXPECT_EQ("", human_readable_name);
EXPECT_EQ("1280x800", pixel.ToString());
EXPECT_EQ("261x163", size.ToString());
// Internal display doesn't have name. // Internal display doesn't have name.
EXPECT_TRUE(ParseOutputDeviceData(edid, NULL, &human_readable_name)); EXPECT_TRUE(ParseOutputDeviceData(edid, nullptr, &human_readable_name, &pixel,
&size));
EXPECT_TRUE(human_readable_name.empty()); EXPECT_TRUE(human_readable_name.empty());
manufacturer_id = 0; manufacturer_id = 0;
human_readable_name.clear(); human_readable_name.clear();
Reset(&pixel, &size);
edid.assign(kOverscanDisplay, kOverscanDisplay + charsize(kOverscanDisplay)); edid.assign(kOverscanDisplay, kOverscanDisplay + charsize(kOverscanDisplay));
EXPECT_TRUE(ParseOutputDeviceData( EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id,
edid, &manufacturer_id, &human_readable_name)); &human_readable_name, &pixel, &size));
EXPECT_EQ(0x4c2du, manufacturer_id); EXPECT_EQ(0x4c2du, manufacturer_id);
EXPECT_EQ("SAMSUNG", human_readable_name); EXPECT_EQ("SAMSUNG", human_readable_name);
EXPECT_EQ("1920x1080", pixel.ToString());
EXPECT_EQ("160x90", size.ToString());
} }
TEST(EDIDParserTest, ParseBrokenEDID) { TEST(EDIDParserTest, ParseBrokenEDID) {
...@@ -179,9 +198,11 @@ TEST(EDIDParserTest, ParseBrokenEDID) { ...@@ -179,9 +198,11 @@ TEST(EDIDParserTest, ParseBrokenEDID) {
std::string human_readable_name; std::string human_readable_name;
std::vector<uint8_t> edid; std::vector<uint8_t> edid;
gfx::Size dummy;
// length == 0 // length == 0
EXPECT_FALSE(ParseOutputDeviceData( EXPECT_FALSE(ParseOutputDeviceData(edid, &manufacturer_id,
edid, &manufacturer_id, &human_readable_name)); &human_readable_name, &dummy, &dummy));
// name is broken. Copying kNormalDisplay and substitute its name data by // name is broken. Copying kNormalDisplay and substitute its name data by
// some control code. // some control code.
...@@ -190,12 +211,13 @@ TEST(EDIDParserTest, ParseBrokenEDID) { ...@@ -190,12 +211,13 @@ TEST(EDIDParserTest, ParseBrokenEDID) {
// display's name data is embedded in byte 95-107 in this specific example. // display's name data is embedded in byte 95-107 in this specific example.
// Fix here too when the contents of kNormalDisplay is altered. // Fix here too when the contents of kNormalDisplay is altered.
edid[97] = '\x1b'; edid[97] = '\x1b';
EXPECT_FALSE(ParseOutputDeviceData( EXPECT_FALSE(ParseOutputDeviceData(edid, &manufacturer_id,
edid, &manufacturer_id, &human_readable_name)); &human_readable_name, &dummy, &dummy));
// If |human_readable_name| isn't specified, it skips parsing the name. // If |human_readable_name| isn't specified, it skips parsing the name.
manufacturer_id = 0; manufacturer_id = 0;
EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, NULL)); EXPECT_TRUE(
ParseOutputDeviceData(edid, &manufacturer_id, nullptr, &dummy, &dummy));
EXPECT_EQ(0x22f0u, manufacturer_id); EXPECT_EQ(0x22f0u, manufacturer_id);
} }
......
...@@ -54,7 +54,7 @@ bool GetEDIDProperty(XID output, std::vector<uint8_t>* edid) { ...@@ -54,7 +54,7 @@ bool GetEDIDProperty(XID output, std::vector<uint8_t>* edid) {
int actual_format; int actual_format;
unsigned long bytes_after; unsigned long bytes_after;
unsigned long nitems = 0; unsigned long nitems = 0;
unsigned char* prop = NULL; unsigned char* prop = nullptr;
XRRGetOutputProperty(display, XRRGetOutputProperty(display,
output, output,
edid_property, edid_property,
...@@ -78,7 +78,7 @@ bool GetEDIDProperty(XID output, std::vector<uint8_t>* edid) { ...@@ -78,7 +78,7 @@ bool GetEDIDProperty(XID output, std::vector<uint8_t>* edid) {
// Gets some useful data from the specified output device, such like // Gets some useful data from the specified output device, such like
// manufacturer's ID, product code, and human readable name. Returns false if it // manufacturer's ID, product code, and human readable name. Returns false if it
// fails to get those data and doesn't touch manufacturer ID/product code/name. // fails to get those data and doesn't touch manufacturer ID/product code/name.
// NULL can be passed for unwanted output parameters. // nullptr can be passed for unwanted output parameters.
bool GetOutputDeviceData(XID output, bool GetOutputDeviceData(XID output,
uint16_t* manufacturer_id, uint16_t* manufacturer_id,
std::string* human_readable_name) { std::string* human_readable_name) {
...@@ -86,9 +86,8 @@ bool GetOutputDeviceData(XID output, ...@@ -86,9 +86,8 @@ bool GetOutputDeviceData(XID output,
if (!GetEDIDProperty(output, &edid)) if (!GetEDIDProperty(output, &edid))
return false; return false;
bool result = ParseOutputDeviceData( return ParseOutputDeviceData(edid, manufacturer_id, human_readable_name,
edid, manufacturer_id, human_readable_name); nullptr, nullptr);
return result;
} }
} // namespace } // namespace
...@@ -106,7 +105,7 @@ bool GetDisplayId(XID output_id, ...@@ -106,7 +105,7 @@ bool GetDisplayId(XID output_id,
std::string GetDisplayName(RROutput output) { std::string GetDisplayName(RROutput output) {
std::string display_name; std::string display_name;
GetOutputDeviceData(output, NULL, &display_name); GetOutputDeviceData(output, nullptr, &display_name);
return display_name; return display_name;
} }
......
...@@ -171,6 +171,7 @@ action("generate_constructor_list") { ...@@ -171,6 +171,7 @@ action("generate_constructor_list") {
test("ozone_unittests") { test("ozone_unittests") {
sources = [ sources = [
"common/display_util_unittest.cc",
"run_all_unittests.cc", "run_all_unittests.cc",
] ]
......
...@@ -3,6 +3,7 @@ include_rules = [ ...@@ -3,6 +3,7 @@ include_rules = [
"+third_party/khronos", "+third_party/khronos",
"+third_party/skia", "+third_party/skia",
"+ui/display/types", "+ui/display/types",
"+ui/display/util",
"+ui/events", "+ui/events",
"+ui/gfx", "+ui/gfx",
"+ui/base/cursor", "+ui/base/cursor",
......
...@@ -5,8 +5,12 @@ ...@@ -5,8 +5,12 @@
#include "ui/ozone/common/display_util.h" #include "ui/ozone/common/display_util.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "ui/display/types/display_mode.h" #include "ui/display/types/display_mode.h"
#include "ui/display/types/display_snapshot.h" #include "ui/display/types/display_snapshot.h"
#include "ui/display/util/edid_parser.h"
#include "ui/display/util/edid_parser.h"
#include "ui/ozone/public/ozone_switches.h" #include "ui/ozone/public/ozone_switches.h"
namespace ui { namespace ui {
...@@ -59,25 +63,19 @@ DisplaySnapshot_Params GetDisplaySnapshotParams( ...@@ -59,25 +63,19 @@ DisplaySnapshot_Params GetDisplaySnapshotParams(
return params; return params;
} }
DisplaySnapshot_Params CreateSnapshotFromCommandLine() { bool CreateSnapshotFromCommandLine(DisplaySnapshot_Params* snapshot_out) {
DisplaySnapshot_Params display_param;
base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
std::string spec = std::string spec =
cmd->GetSwitchValueASCII(switches::kOzoneInitialDisplayBounds); cmd->GetSwitchValueASCII(switches::kOzoneInitialDisplayBounds);
std::string physical_spec = std::string physical_spec =
cmd->GetSwitchValueASCII(switches::kOzoneInitialDisplayPhysicalSizeMm); cmd->GetSwitchValueASCII(switches::kOzoneInitialDisplayPhysicalSizeMm);
if (spec.empty())
return display_param;
int width = 0; int width = 0;
int height = 0; int height = 0;
if (sscanf(spec.c_str(), "%dx%d", &width, &height) < 2) if (spec.empty() || sscanf(spec.c_str(), "%dx%d", &width, &height) < 2 ||
return display_param; width == 0 || height == 0) {
return false;
if (width == 0 || height == 0) }
return display_param;
int physical_width = 0; int physical_width = 0;
int physical_height = 0; int physical_height = 0;
...@@ -87,16 +85,61 @@ DisplaySnapshot_Params CreateSnapshotFromCommandLine() { ...@@ -87,16 +85,61 @@ DisplaySnapshot_Params CreateSnapshotFromCommandLine() {
mode_param.size = gfx::Size(width, height); mode_param.size = gfx::Size(width, height);
mode_param.refresh_rate = 60; mode_param.refresh_rate = 60;
display_param.display_id = kDummyDisplayId; snapshot_out->display_id = kDummyDisplayId;
display_param.modes.push_back(mode_param); snapshot_out->modes.push_back(mode_param);
display_param.type = DISPLAY_CONNECTION_TYPE_INTERNAL; snapshot_out->type = DISPLAY_CONNECTION_TYPE_INTERNAL;
display_param.physical_size = gfx::Size(physical_width, physical_height); snapshot_out->physical_size = gfx::Size(physical_width, physical_height);
display_param.has_current_mode = true; snapshot_out->has_current_mode = true;
display_param.current_mode = mode_param; snapshot_out->current_mode = mode_param;
display_param.has_native_mode = true; snapshot_out->has_native_mode = true;
display_param.native_mode = mode_param; snapshot_out->native_mode = mode_param;
return true;
}
bool CreateSnapshotFromEDID(bool internal,
const std::vector<uint8_t>& edid,
DisplaySnapshot_Params* snapshot_out) {
uint16_t manufacturer_id = 0;
gfx::Size resolution;
DisplayMode_Params mode_param;
mode_param.refresh_rate = 60.0f;
if (!ParseOutputDeviceData(edid, &manufacturer_id,
&snapshot_out->display_name, &mode_param.size,
&snapshot_out->physical_size) ||
!GetDisplayIdFromEDID(edid, 0, &snapshot_out->display_id)) {
return false;
}
ParseOutputOverscanFlag(edid, &snapshot_out->has_overscan);
snapshot_out->modes.push_back(mode_param);
// Use VGA for external display for now.
// TODO(oshima): frecon should set this value in the display_info.bin file.
snapshot_out->type =
internal ? DISPLAY_CONNECTION_TYPE_INTERNAL : DISPLAY_CONNECTION_TYPE_VGA;
snapshot_out->has_current_mode = true;
snapshot_out->current_mode = mode_param;
snapshot_out->has_native_mode = true;
snapshot_out->native_mode = mode_param;
return true;
}
return display_param; bool CreateSnapshotFromEDIDFile(const base::FilePath& file,
DisplaySnapshot_Params* snapshot_out) {
std::string raw_display_info;
const int kEDIDMaxSize = 128;
if (!base::ReadFileToString(file, &raw_display_info, kEDIDMaxSize + 1) ||
raw_display_info.size() < 10) {
return false;
}
std::vector<uint8_t> edid;
// The head of the file contains one byte flag that indicates the type of
// display.
bool internal = raw_display_info[0] == 1;
edid.assign(raw_display_info.c_str() + 1,
raw_display_info.c_str() + raw_display_info.size());
return CreateSnapshotFromEDID(internal, edid, snapshot_out);
} }
} // namespace ui } // namespace ui
...@@ -5,8 +5,14 @@ ...@@ -5,8 +5,14 @@
#ifndef UI_OZONE_COMMON_DISPLAY_UTIL_H_ #ifndef UI_OZONE_COMMON_DISPLAY_UTIL_H_
#define UI_OZONE_COMMON_DISPLAY_UTIL_H_ #define UI_OZONE_COMMON_DISPLAY_UTIL_H_
#include <vector>
#include "ui/ozone/common/gpu/ozone_gpu_message_params.h" #include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
namespace base {
class FilePath;
}
namespace ui { namespace ui {
class DisplayMode; class DisplayMode;
...@@ -28,7 +34,19 @@ DisplayMode_Params GetDisplayModeParams(const DisplayMode& mode); ...@@ -28,7 +34,19 @@ DisplayMode_Params GetDisplayModeParams(const DisplayMode& mode);
DisplaySnapshot_Params GetDisplaySnapshotParams(const DisplaySnapshot& display); DisplaySnapshot_Params GetDisplaySnapshotParams(const DisplaySnapshot& display);
// Create a display using the Ozone command line parameters. // Create a display using the Ozone command line parameters.
DisplaySnapshot_Params CreateSnapshotFromCommandLine(); // Return false if the command line flags are not specified.
bool CreateSnapshotFromCommandLine(DisplaySnapshot_Params* snapshot_out);
// Create a display snapshot from |file| that contains EDID.
// Return false if the file doesn't exist, or it doesn't contain valid EDID.
bool CreateSnapshotFromEDIDFile(const base::FilePath& file,
DisplaySnapshot_Params* snapshot_out);
// Create a display snaphot from edid.
// Return false if it doesn't contain valid EDID.
bool CreateSnapshotFromEDID(bool internal,
const std::vector<uint8_t>& edid,
DisplaySnapshot_Params* snapshot_out);
} // namespace ui } // namespace ui
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/common/display_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
typedef testing::Test DisplayUtilTest;
namespace ui {
namespace {
// EDID from HP ZR30w
const unsigned char kTestEDID[] =
"\x00\xff\xff\xff\xff\xff\xff\x00\x22\xf0\x6c\x28\x01\x01\x01\x01"
"\x02\x16\x01\x04\xb5\x40\x28\x78\xe2\x8d\x85\xad\x4f\x35\xb1\x25"
"\x0e\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x01\x01\xe2\x68\x00\xa0\xa0\x40\x2e\x60\x30\x20"
"\x36\x00\x81\x90\x21\x00\x00\x1a\xbc\x1b\x00\xa0\x50\x20\x17\x30"
"\x30\x20\x36\x00\x81\x90\x21\x00\x00\x1a\x00\x00\x00\xfc\x00\x48"
"\x50\x20\x5a\x52\x33\x30\x77\x0a\x20\x20\x20\x20\x00\x00\x00\xff"
"\x00\x43\x4e\x34\x32\x30\x32\x31\x33\x37\x51\x0a\x20\x20\x00\x71";
} // namespace
TEST_F(DisplayUtilTest, BasicEDID) {
DisplaySnapshot_Params params;
// -1 to skip NULL byte.
std::vector<uint8_t> edid(kTestEDID, kTestEDID + arraysize(kTestEDID) - 1);
// External Display
EXPECT_TRUE(CreateSnapshotFromEDID(true, edid, &params));
EXPECT_EQ("HP ZR30w", params.display_name);
EXPECT_EQ(1u, params.modes.size());
EXPECT_TRUE(params.has_current_mode);
EXPECT_EQ("2560x1600", params.current_mode.size.ToString());
EXPECT_EQ("641x400", params.physical_size.ToString());
EXPECT_EQ(DISPLAY_CONNECTION_TYPE_INTERNAL, params.type);
// Reset
params = DisplaySnapshot_Params();
// External Display
EXPECT_TRUE(CreateSnapshotFromEDID(false, edid, &params));
EXPECT_EQ("HP ZR30w", params.display_name);
EXPECT_EQ(1u, params.modes.size());
EXPECT_TRUE(params.has_current_mode);
EXPECT_EQ("2560x1600", params.current_mode.size.ToString());
EXPECT_EQ("641x400", params.physical_size.ToString());
EXPECT_EQ(DISPLAY_CONNECTION_TYPE_VGA, params.type);
}
TEST_F(DisplayUtilTest, EmptyEDID) {
DisplaySnapshot_Params params;
std::vector<uint8_t> edid;
EXPECT_FALSE(CreateSnapshotFromEDID(true, std::vector<uint8_t>(), &params));
}
} // namespace ui
...@@ -17,9 +17,11 @@ NativeDisplayDelegateOzone::~NativeDisplayDelegateOzone() { ...@@ -17,9 +17,11 @@ NativeDisplayDelegateOzone::~NativeDisplayDelegateOzone() {
} }
void NativeDisplayDelegateOzone::Initialize() { void NativeDisplayDelegateOzone::Initialize() {
DisplaySnapshot_Params params = CreateSnapshotFromCommandLine(); DisplaySnapshot_Params params;
if (params.type != DISPLAY_CONNECTION_TYPE_NONE) if (CreateSnapshotFromCommandLine(&params)) {
DCHECK_NE(DISPLAY_CONNECTION_TYPE_NONE, params.type);
displays_.push_back(new DisplaySnapshotProxy(params)); displays_.push_back(new DisplaySnapshotProxy(params));
}
} }
void NativeDisplayDelegateOzone::GrabServer() { void NativeDisplayDelegateOzone::GrabServer() {
......
...@@ -174,10 +174,11 @@ ...@@ -174,10 +174,11 @@
'target_name': 'ozone_unittests', 'target_name': 'ozone_unittests',
'type': '<(gtest_target_type)', 'type': '<(gtest_target_type)',
'sources': [ 'sources': [
'common/display_util_unittest.cc',
'run_all_unittests.cc', 'run_all_unittests.cc',
], ],
'dependencies': [ 'dependencies': [
'ozone_base', 'ozone',
'../../base/base.gyp:base', '../../base/base.gyp:base',
'../../base/base.gyp:test_support_base', '../../base/base.gyp:test_support_base',
'../../testing/gtest.gyp:gtest', '../../testing/gtest.gyp:gtest',
......
...@@ -79,8 +79,8 @@ DisplaySnapshotDri::DisplaySnapshotDri(DriWrapper* drm, ...@@ -79,8 +79,8 @@ DisplaySnapshotDri::DisplaySnapshotDri(DriWrapper* drm,
false, false,
std::string(), std::string(),
std::vector<const DisplayMode*>(), std::vector<const DisplayMode*>(),
NULL, nullptr,
NULL), nullptr),
connector_(connector->connector_id), connector_(connector->connector_id),
crtc_(crtc->crtc_id), crtc_(crtc->crtc_id),
dpms_property_(drm->GetProperty(connector, "DPMS")) { dpms_property_(drm->GetProperty(connector, "DPMS")) {
...@@ -98,7 +98,7 @@ DisplaySnapshotDri::DisplaySnapshotDri(DriWrapper* drm, ...@@ -98,7 +98,7 @@ DisplaySnapshotDri::DisplaySnapshotDri(DriWrapper* drm,
if (!GetDisplayIdFromEDID(edid, index, &display_id_)) if (!GetDisplayIdFromEDID(edid, index, &display_id_))
display_id_ = index; display_id_ = index;
ParseOutputDeviceData(edid, NULL, &display_name_); ParseOutputDeviceData(edid, nullptr, &display_name_, nullptr, nullptr);
ParseOutputOverscanFlag(edid, &overscan_flag_); ParseOutputOverscanFlag(edid, &overscan_flag_);
} else { } else {
VLOG(1) << "Failed to get EDID blob for connector " VLOG(1) << "Failed to get EDID blob for connector "
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <stdio.h> #include <stdio.h>
#include "base/logging.h" #include "base/logging.h"
#include "base/threading/thread_restrictions.h"
#include "ui/display/types/display_snapshot.h" #include "ui/display/types/display_snapshot.h"
#include "ui/display/types/native_display_observer.h" #include "ui/display/types/native_display_observer.h"
#include "ui/events/ozone/device/device_event.h" #include "ui/events/ozone/device/device_event.h"
...@@ -63,9 +64,22 @@ void NativeDisplayDelegateProxy::Initialize() { ...@@ -63,9 +64,22 @@ void NativeDisplayDelegateProxy::Initialize() {
if (!displays_.empty()) if (!displays_.empty())
return; return;
DisplaySnapshot_Params params;
bool success = false;
{
// The file generated by frecon that contains EDID for the 1st display.
const base::FilePath kEDIDFile("/tmp/display_info.bin");
// Just read it on current thread as this is necessary information
// to start. This access only tmpfs, which is fast.
// TODO(dnicoara|oshima): crbug.com/450886.
base::ThreadRestrictions::ScopedAllowIO allow_io;
success = CreateSnapshotFromEDIDFile(kEDIDFile, &params);
}
DisplaySnapshot_Params params = CreateSnapshotFromCommandLine(); // Fallback to command line if the file doesn't exit or failed to read.
if (params.type != DISPLAY_CONNECTION_TYPE_NONE) { if (success || CreateSnapshotFromCommandLine(&params)) {
DCHECK_NE(DISPLAY_CONNECTION_TYPE_NONE, params.type);
displays_.push_back(new DriDisplaySnapshotProxy(params, display_manager_)); displays_.push_back(new DriDisplaySnapshotProxy(params, display_manager_));
has_dummy_display_ = true; has_dummy_display_ = true;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment