OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/display/display_color_manager_chromeos.h" | 5 #include "ash/display/display_color_manager_chromeos.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
13 #include "base/task_runner_util.h" | 13 #include "base/task_runner_util.h" |
14 #include "base/threading/sequenced_worker_pool.h" | 14 #include "base/threading/sequenced_worker_pool.h" |
15 #include "components/quirks/quirks_manager.h" | 15 #include "components/quirks/quirks_manager.h" |
16 #include "third_party/qcms/src/qcms.h" | 16 #include "third_party/qcms/src/qcms.h" |
17 #include "ui/display/types/display_snapshot.h" | 17 #include "ui/display/types/display_snapshot.h" |
18 #include "ui/display/types/gamma_ramp_rgb_entry.h" | 18 #include "ui/display/types/gamma_ramp_rgb_entry.h" |
19 #include "ui/gfx/display.h" | 19 #include "ui/gfx/display.h" |
20 | 20 |
21 namespace ash { | 21 namespace ash { |
22 | 22 |
23 namespace { | 23 namespace { |
24 | 24 |
25 scoped_ptr<DisplayColorManager::ColorCalibrationData> ParseDisplayProfile( | 25 scoped_ptr<DisplayColorManager::ColorCalibrationData> ParseDisplayProfile( |
26 const base::FilePath& path) { | 26 const base::FilePath& path, |
| 27 bool has_color_correction_matrix) { |
| 28 VLOG(1) << "Trying ICC file " << path.value() |
| 29 << " has_color_correction_matrix: " |
| 30 << (has_color_correction_matrix ? "true" : "false"); |
27 qcms_profile* display_profile = qcms_profile_from_path(path.value().c_str()); | 31 qcms_profile* display_profile = qcms_profile_from_path(path.value().c_str()); |
28 if (!display_profile) { | 32 if (!display_profile) { |
29 LOG(WARNING) << "Unable to load ICC file: " << path.value(); | 33 LOG(WARNING) << "Unable to load ICC file: " << path.value(); |
30 return nullptr; | 34 return nullptr; |
31 } | 35 } |
32 | 36 |
33 size_t vcgt_channel_length = | 37 size_t vcgt_channel_length = |
34 qcms_profile_get_vcgt_channel_length(display_profile); | 38 qcms_profile_get_vcgt_channel_length(display_profile); |
35 if (!vcgt_channel_length) { | 39 |
| 40 if (!has_color_correction_matrix && !vcgt_channel_length) { |
36 LOG(WARNING) << "No vcgt table in ICC file: " << path.value(); | 41 LOG(WARNING) << "No vcgt table in ICC file: " << path.value(); |
37 qcms_profile_release(display_profile); | 42 qcms_profile_release(display_profile); |
38 return nullptr; | 43 return nullptr; |
39 } | 44 } |
40 | 45 |
41 std::vector<uint16_t> vcgt_data; | |
42 vcgt_data.resize(vcgt_channel_length * 3); | |
43 if (!qcms_profile_get_vcgt_rgb_channels(display_profile, &vcgt_data[0])) { | |
44 LOG(WARNING) << "Unable to get vcgt data"; | |
45 qcms_profile_release(display_profile); | |
46 return nullptr; | |
47 } | |
48 | |
49 scoped_ptr<DisplayColorManager::ColorCalibrationData> data( | 46 scoped_ptr<DisplayColorManager::ColorCalibrationData> data( |
50 new DisplayColorManager::ColorCalibrationData()); | 47 new DisplayColorManager::ColorCalibrationData()); |
51 data->lut.resize(vcgt_channel_length); | 48 if (vcgt_channel_length) { |
52 for (size_t i = 0; i < vcgt_channel_length; ++i) { | 49 VLOG_IF(1, has_color_correction_matrix) |
53 data->lut[i].r = vcgt_data[i]; | 50 << "Using VCGT data on CTM enabled platform."; |
54 data->lut[i].g = vcgt_data[vcgt_channel_length + i]; | 51 |
55 data->lut[i].b = vcgt_data[(vcgt_channel_length * 2) + i]; | 52 std::vector<uint16_t> vcgt_data; |
| 53 vcgt_data.resize(vcgt_channel_length * 3); |
| 54 if (!qcms_profile_get_vcgt_rgb_channels(display_profile, &vcgt_data[0])) { |
| 55 LOG(WARNING) << "Unable to get vcgt data"; |
| 56 qcms_profile_release(display_profile); |
| 57 return nullptr; |
| 58 } |
| 59 |
| 60 data->gamma_lut.resize(vcgt_channel_length); |
| 61 for (size_t i = 0; i < vcgt_channel_length; ++i) { |
| 62 data->gamma_lut[i].r = vcgt_data[i]; |
| 63 data->gamma_lut[i].g = vcgt_data[vcgt_channel_length + i]; |
| 64 data->gamma_lut[i].b = vcgt_data[(vcgt_channel_length * 2) + i]; |
| 65 } |
| 66 } else { |
| 67 VLOG(1) << "Using full degamma/gamma/CTM from profile."; |
| 68 qcms_profile* srgb_profile = qcms_profile_sRGB(); |
| 69 |
| 70 qcms_transform* transform = |
| 71 qcms_transform_create(srgb_profile, QCMS_DATA_RGB_8, display_profile, |
| 72 QCMS_DATA_RGB_8, QCMS_INTENT_PERCEPTUAL); |
| 73 |
| 74 if (!transform) { |
| 75 LOG(WARNING) |
| 76 << "Unable to create transformation from sRGB to display profile."; |
| 77 |
| 78 qcms_profile_release(display_profile); |
| 79 qcms_profile_release(srgb_profile); |
| 80 return nullptr; |
| 81 } |
| 82 |
| 83 if (!qcms_transform_is_matrix(transform)) { |
| 84 LOG(WARNING) << "No transformation matrix available"; |
| 85 |
| 86 qcms_transform_release(transform); |
| 87 qcms_profile_release(display_profile); |
| 88 qcms_profile_release(srgb_profile); |
| 89 return nullptr; |
| 90 } |
| 91 |
| 92 size_t degamma_size = qcms_transform_get_input_trc_rgba( |
| 93 transform, srgb_profile, QCMS_TRC_USHORT, NULL); |
| 94 size_t gamma_size = qcms_transform_get_output_trc_rgba( |
| 95 transform, display_profile, QCMS_TRC_USHORT, NULL); |
| 96 |
| 97 if (degamma_size == 0 || gamma_size == 0) { |
| 98 LOG(WARNING) |
| 99 << "Invalid number of elements in gamma tables: degamma size = " |
| 100 << degamma_size << " gamma size = " << gamma_size; |
| 101 |
| 102 qcms_transform_release(transform); |
| 103 qcms_profile_release(display_profile); |
| 104 qcms_profile_release(srgb_profile); |
| 105 return nullptr; |
| 106 } |
| 107 |
| 108 std::vector<uint16_t> degamma_data; |
| 109 std::vector<uint16_t> gamma_data; |
| 110 degamma_data.resize(degamma_size * 4); |
| 111 gamma_data.resize(gamma_size * 4); |
| 112 |
| 113 qcms_transform_get_input_trc_rgba(transform, srgb_profile, QCMS_TRC_USHORT, |
| 114 °amma_data[0]); |
| 115 qcms_transform_get_output_trc_rgba(transform, display_profile, |
| 116 QCMS_TRC_USHORT, &gamma_data[0]); |
| 117 |
| 118 data->degamma_lut.resize(degamma_size); |
| 119 for (size_t i = 0; i < degamma_size; ++i) { |
| 120 data->degamma_lut[i].r = degamma_data[i * 4]; |
| 121 data->degamma_lut[i].g = degamma_data[(i * 4) + 1]; |
| 122 data->degamma_lut[i].b = degamma_data[(i * 4) + 2]; |
| 123 } |
| 124 |
| 125 data->gamma_lut.resize(gamma_size); |
| 126 for (size_t i = 0; i < gamma_size; ++i) { |
| 127 data->gamma_lut[i].r = gamma_data[i * 4]; |
| 128 data->gamma_lut[i].g = gamma_data[(i * 4) + 1]; |
| 129 data->gamma_lut[i].b = gamma_data[(i * 4) + 2]; |
| 130 } |
| 131 |
| 132 data->correction_matrix.resize(9); |
| 133 for (int i = 0; i < 9; ++i) { |
| 134 data->correction_matrix[i] = |
| 135 qcms_transform_get_matrix(transform, i / 3, i % 3); |
| 136 } |
| 137 |
| 138 qcms_transform_release(transform); |
| 139 qcms_profile_release(srgb_profile); |
56 } | 140 } |
| 141 |
| 142 VLOG(1) << "ICC file successfully parsed"; |
57 qcms_profile_release(display_profile); | 143 qcms_profile_release(display_profile); |
58 VLOG(1) << "Gamma data successfully read from icc file"; | |
59 return data; | 144 return data; |
60 } | 145 } |
61 | 146 |
62 } // namespace | 147 } // namespace |
63 | 148 |
64 DisplayColorManager::DisplayColorManager( | 149 DisplayColorManager::DisplayColorManager( |
65 ui::DisplayConfigurator* configurator, | 150 ui::DisplayConfigurator* configurator, |
66 base::SequencedWorkerPool* blocking_pool) | 151 base::SequencedWorkerPool* blocking_pool) |
67 : configurator_(configurator), | 152 : configurator_(configurator), |
68 blocking_pool_(blocking_pool), | 153 blocking_pool_(blocking_pool), |
(...skipping 14 matching lines...) Expand all Loading... |
83 } else { | 168 } else { |
84 if (state->product_id() != ui::DisplaySnapshot::kInvalidProductID) | 169 if (state->product_id() != ui::DisplaySnapshot::kInvalidProductID) |
85 LoadCalibrationForDisplay(state); | 170 LoadCalibrationForDisplay(state); |
86 } | 171 } |
87 } | 172 } |
88 } | 173 } |
89 | 174 |
90 void DisplayColorManager::ApplyDisplayColorCalibration(int64_t display_id, | 175 void DisplayColorManager::ApplyDisplayColorCalibration(int64_t display_id, |
91 int64_t product_id) { | 176 int64_t product_id) { |
92 if (calibration_map_.find(product_id) != calibration_map_.end()) { | 177 if (calibration_map_.find(product_id) != calibration_map_.end()) { |
93 ColorCalibrationData* ramp = calibration_map_[product_id]; | 178 ColorCalibrationData* data = calibration_map_[product_id]; |
94 if (!configurator_->SetGammaRamp(display_id, ramp->lut)) | 179 if (!configurator_->SetColorCorrection(display_id, data->degamma_lut, |
95 LOG(WARNING) << "Error applying gamma ramp"; | 180 data->gamma_lut, |
| 181 data->correction_matrix)) |
| 182 LOG(WARNING) << "Error applying color correction data"; |
96 } | 183 } |
97 } | 184 } |
98 | 185 |
99 void DisplayColorManager::LoadCalibrationForDisplay( | 186 void DisplayColorManager::LoadCalibrationForDisplay( |
100 const ui::DisplaySnapshot* display) { | 187 const ui::DisplaySnapshot* display) { |
101 DCHECK(thread_checker_.CalledOnValidThread()); | 188 DCHECK(thread_checker_.CalledOnValidThread()); |
102 if (display->display_id() == gfx::Display::kInvalidDisplayID) { | 189 if (display->display_id() == gfx::Display::kInvalidDisplayID) { |
103 LOG(WARNING) << "Trying to load calibration data for invalid display id"; | 190 LOG(WARNING) << "Trying to load calibration data for invalid display id"; |
104 return; | 191 return; |
105 } | 192 } |
106 | 193 |
107 quirks::QuirksManager::Get()->RequestIccProfilePath( | 194 quirks::QuirksManager::Get()->RequestIccProfilePath( |
108 display->product_id(), | 195 display->product_id(), |
109 base::Bind(&DisplayColorManager::FinishLoadCalibrationForDisplay, | 196 base::Bind(&DisplayColorManager::FinishLoadCalibrationForDisplay, |
110 weak_ptr_factory_.GetWeakPtr(), display->display_id(), | 197 weak_ptr_factory_.GetWeakPtr(), display->display_id(), |
111 display->product_id(), display->type())); | 198 display->product_id(), display->has_color_correction_matrix(), |
| 199 display->type())); |
112 } | 200 } |
113 | 201 |
114 void DisplayColorManager::FinishLoadCalibrationForDisplay( | 202 void DisplayColorManager::FinishLoadCalibrationForDisplay( |
115 int64_t display_id, | 203 int64_t display_id, |
116 int64_t product_id, | 204 int64_t product_id, |
| 205 bool has_color_correction_matrix, |
117 ui::DisplayConnectionType type, | 206 ui::DisplayConnectionType type, |
118 const base::FilePath& path, | 207 const base::FilePath& path, |
119 bool file_downloaded) { | 208 bool file_downloaded) { |
120 DCHECK(thread_checker_.CalledOnValidThread()); | 209 DCHECK(thread_checker_.CalledOnValidThread()); |
121 std::string product_string = quirks::IdToHexString(product_id); | 210 std::string product_string = quirks::IdToHexString(product_id); |
122 if (path.empty()) { | 211 if (path.empty()) { |
123 VLOG(1) << "No ICC file found with product id: " << product_string | 212 VLOG(1) << "No ICC file found with product id: " << product_string |
124 << " for display id: " << display_id; | 213 << " for display id: " << display_id; |
125 return; | 214 return; |
126 } | 215 } |
127 | 216 |
128 if (file_downloaded && type == ui::DISPLAY_CONNECTION_TYPE_INTERNAL) { | 217 if (file_downloaded && type == ui::DISPLAY_CONNECTION_TYPE_INTERNAL) { |
129 VLOG(1) << "Downloaded ICC file with product id: " << product_string | 218 VLOG(1) << "Downloaded ICC file with product id: " << product_string |
130 << " for internal display id: " << display_id | 219 << " for internal display id: " << display_id |
131 << ". Profile will be applied on next startup."; | 220 << ". Profile will be applied on next startup."; |
132 return; | 221 return; |
133 } | 222 } |
134 | 223 |
135 VLOG(1) << "Loading ICC file " << path.value() | 224 VLOG(1) << "Loading ICC file " << path.value() |
136 << " for display id: " << display_id | 225 << " for display id: " << display_id |
137 << " with product id: " << product_string; | 226 << " with product id: " << product_string; |
138 | 227 |
139 base::PostTaskAndReplyWithResult( | 228 base::PostTaskAndReplyWithResult( |
140 blocking_pool_, FROM_HERE, base::Bind(&ParseDisplayProfile, path), | 229 blocking_pool_, FROM_HERE, |
| 230 base::Bind(&ParseDisplayProfile, path, has_color_correction_matrix), |
141 base::Bind(&DisplayColorManager::UpdateCalibrationData, | 231 base::Bind(&DisplayColorManager::UpdateCalibrationData, |
142 weak_ptr_factory_.GetWeakPtr(), display_id, product_id)); | 232 weak_ptr_factory_.GetWeakPtr(), display_id, product_id)); |
143 } | 233 } |
144 | 234 |
145 void DisplayColorManager::UpdateCalibrationData( | 235 void DisplayColorManager::UpdateCalibrationData( |
146 int64_t display_id, | 236 int64_t display_id, |
147 int64_t product_id, | 237 int64_t product_id, |
148 scoped_ptr<ColorCalibrationData> data) { | 238 scoped_ptr<ColorCalibrationData> data) { |
149 DCHECK(thread_checker_.CalledOnValidThread()); | 239 DCHECK(thread_checker_.CalledOnValidThread()); |
150 if (data) { | 240 if (data) { |
151 // The map takes over ownership of the underlying memory. | 241 // The map takes over ownership of the underlying memory. |
152 calibration_map_[product_id] = data.release(); | 242 calibration_map_[product_id] = data.release(); |
153 ApplyDisplayColorCalibration(display_id, product_id); | 243 ApplyDisplayColorCalibration(display_id, product_id); |
154 } | 244 } |
155 } | 245 } |
156 | 246 |
157 DisplayColorManager::ColorCalibrationData::ColorCalibrationData() {} | 247 DisplayColorManager::ColorCalibrationData::ColorCalibrationData() {} |
158 | 248 |
159 DisplayColorManager::ColorCalibrationData::~ColorCalibrationData() {} | 249 DisplayColorManager::ColorCalibrationData::~ColorCalibrationData() {} |
160 | 250 |
161 } // namespace ash | 251 } // namespace ash |
OLD | NEW |