Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(869)

Side by Side Diff: chromeos/display/output_configurator.cc

Issue 10909242: Add "panel_fitting" GPU feature type and use it for mirror mode. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Addressed review comments of Patch Set 2 Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chromeos/display/output_configurator.h" 5 #include "chromeos/display/output_configurator.h"
6 6
7 #include <X11/Xlib.h> 7 #include <X11/Xlib.h>
8 #include <X11/extensions/dpms.h> 8 #include <X11/extensions/dpms.h>
9 #include <X11/extensions/Xrandr.h> 9 #include <X11/extensions/Xrandr.h>
10 10
11 // Xlib defines Status as int which causes our include of dbus/bus.h to fail 11 // Xlib defines Status as int which causes our include of dbus/bus.h to fail
12 // when it tries to name an enum Status. Thus, we need to undefine it (note 12 // when it tries to name an enum Status. Thus, we need to undefine it (note
13 // that this will cause a problem if code needs to use the Status type). 13 // that this will cause a problem if code needs to use the Status type).
14 // RootWindow causes similar problems in that there is a Chromium type with that 14 // RootWindow causes similar problems in that there is a Chromium type with that
15 // name. 15 // name.
16 #undef Status 16 #undef Status
17 #undef RootWindow 17 #undef RootWindow
18 18
19 #include "base/bind.h" 19 #include "base/bind.h"
20 #include "base/chromeos/chromeos_version.h" 20 #include "base/chromeos/chromeos_version.h"
21 #include "base/logging.h" 21 #include "base/logging.h"
22 #include "base/message_pump_aurax11.h" 22 #include "base/message_pump_aurax11.h"
23 #include "base/metrics/histogram.h" 23 #include "base/metrics/histogram.h"
24 #include "base/perftimer.h" 24 #include "base/perftimer.h"
25 #include "chromeos/dbus/dbus_thread_manager.h" 25 #include "chromeos/dbus/dbus_thread_manager.h"
26 #include "chromeos/dbus/power_manager_client.h" 26 #include "chromeos/dbus/power_manager_client.h"
27 27
28 namespace chromeos { 28 namespace chromeos {
29 29
30 typedef struct OutputSnapshot {
31 RROutput output;
32 RRCrtc crtc;
33 RRMode current_mode;
34 int height;
35 int y;
36 RRMode native_mode;
37 RRMode mirror_mode;
38 bool is_internal;
39 } OutputSnapshot;
40
30 namespace { 41 namespace {
31 // DPI measurements. 42 // DPI measurements.
32 const float kMmInInch = 25.4; 43 const float kMmInInch = 25.4;
33 const float kDpi96 = 96.0; 44 const float kDpi96 = 96.0;
34 const float kPixelsToMmScale = kMmInInch / kDpi96; 45 const float kPixelsToMmScale = kMmInInch / kDpi96;
35 46
36 // The DPI threshold to detech high density screen. 47 // The DPI threshold to detech high density screen.
37 // Higher DPI than this will use device_scale_factor=2 48 // Higher DPI than this will use device_scale_factor=2
38 // Should be kept in sync with display_change_observer_x11.cc 49 // Should be kept in sync with display_change_observer_x11.cc
39 const unsigned int kHighDensityDIPThreshold = 160; 50 const unsigned int kHighDensityDIPThreshold = 160;
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 x, 198 x,
188 y, 199 y,
189 kMode, 200 kMode,
190 kOutput); 201 kOutput);
191 } 202 }
192 int mm_width = width * kPixelsToMmScale; 203 int mm_width = width * kPixelsToMmScale;
193 int mm_height = height * kPixelsToMmScale; 204 int mm_height = height * kPixelsToMmScale;
194 XRRSetScreenSize(display, window, width, height, mm_width, mm_height); 205 XRRSetScreenSize(display, window, width, height, mm_width, mm_height);
195 } 206 }
196 207
197 typedef struct OutputSnapshot {
198 RROutput output;
199 RRCrtc crtc;
200 RRMode current_mode;
201 int height;
202 int y;
203 RRMode native_mode;
204 RRMode mirror_mode;
205 bool is_internal;
206 } OutputSnapshot;
207
208 static int GetDualOutputs(Display* display,
209 XRRScreenResources* screen,
210 OutputSnapshot* one,
211 OutputSnapshot* two) {
212 int found_count = 0;
213 XRROutputInfo* one_info = NULL;
214 XRROutputInfo* two_info = NULL;
215
216 for (int i = 0; (i < screen->noutput) && (found_count < 2); ++i) {
217 RROutput this_id = screen->outputs[i];
218 XRROutputInfo* output_info = XRRGetOutputInfo(display, screen, this_id);
219 bool is_connected = (RR_Connected == output_info->connection);
220
221 if (is_connected) {
222 OutputSnapshot *to_populate = NULL;
223
224 if (0 == found_count) {
225 to_populate = one;
226 one_info = output_info;
227 } else {
228 to_populate = two;
229 two_info = output_info;
230 }
231
232 to_populate->output = this_id;
233 // Now, look up the corresponding CRTC and any related info.
234 to_populate->crtc = output_info->crtc;
235 if (None != to_populate->crtc) {
236 XRRCrtcInfo* crtc_info =
237 XRRGetCrtcInfo(display, screen, to_populate->crtc);
238 to_populate->current_mode = crtc_info->mode;
239 to_populate->height = crtc_info->height;
240 to_populate->y = crtc_info->y;
241 XRRFreeCrtcInfo(crtc_info);
242 } else {
243 to_populate->current_mode = 0;
244 to_populate->height = 0;
245 to_populate->y = 0;
246 }
247 // Find the native_mode and leave the mirror_mode for the pass after the
248 // loop.
249 if (output_info->nmode > 0)
250 to_populate->native_mode = output_info->modes[0];
251 to_populate->mirror_mode = 0;
252
253 // See if this output refers to an internal display.
254 to_populate->is_internal =
255 OutputConfigurator::IsInternalOutputName(
256 std::string(output_info->name));
257
258 VLOG(1) << "Found display #" << found_count
259 << " with output " << (int)to_populate->output
260 << " crtc " << (int)to_populate->crtc
261 << " current mode " << (int)to_populate->current_mode;
262 ++found_count;
263 } else {
264 XRRFreeOutputInfo(output_info);
265 }
266 }
267
268 if (2 == found_count) {
269 // Find the mirror modes (if there are any).
270 bool can_mirror = FindMirrorModeForOutputs(display,
271 screen,
272 one->output,
273 two->output,
274 &one->mirror_mode,
275 &two->mirror_mode);
276 if (!can_mirror) {
277 // We can't mirror so set mirror_mode to 0.
278 one->mirror_mode = 0;
279 two->mirror_mode = 0;
280 }
281 }
282
283 XRRFreeOutputInfo(one_info);
284 XRRFreeOutputInfo(two_info);
285 return found_count;
286 }
287
288 static OutputState InferCurrentState(Display* display, 208 static OutputState InferCurrentState(Display* display,
289 XRRScreenResources* screen, 209 XRRScreenResources* screen,
290 const OutputSnapshot* outputs, 210 const OutputSnapshot* outputs,
291 int output_count) { 211 int output_count) {
292 OutputState state = STATE_INVALID; 212 OutputState state = STATE_INVALID;
293 switch (output_count) { 213 switch (output_count) {
294 case 0: 214 case 0:
295 state = STATE_HEADLESS; 215 state = STATE_HEADLESS;
296 break; 216 break;
297 case 1: 217 case 1:
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 475
556 // "Projecting" is defined as having more than 1 output connected while at 476 // "Projecting" is defined as having more than 1 output connected while at
557 // least one of them is an internal output. 477 // least one of them is an internal output.
558 return has_internal_output && (connected_output_count > 1); 478 return has_internal_output && (connected_output_count > 1);
559 } 479 }
560 480
561 } // namespace 481 } // namespace
562 482
563 OutputConfigurator::OutputConfigurator() 483 OutputConfigurator::OutputConfigurator()
564 : is_running_on_chrome_os_(base::chromeos::IsRunningOnChromeOS()), 484 : is_running_on_chrome_os_(base::chromeos::IsRunningOnChromeOS()),
485 is_panel_fitting_enabled_(false),
486 connected_output_count_(0),
565 xrandr_event_base_(0), 487 xrandr_event_base_(0),
566 output_state_(STATE_INVALID) { 488 output_state_(STATE_INVALID) {
489 }
490
491 void OutputConfigurator::Init(bool is_panel_fitting_enabled) {
567 if (!is_running_on_chrome_os_) 492 if (!is_running_on_chrome_os_)
568 return; 493 return;
569 494
495 is_panel_fitting_enabled_ = is_panel_fitting_enabled;
496
570 // Cache the initial output state. 497 // Cache the initial output state.
571 Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay(); 498 Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
572 CHECK(display != NULL); 499 CHECK(display != NULL);
573 XGrabServer(display); 500 XGrabServer(display);
574 Window window = DefaultRootWindow(display); 501 Window window = DefaultRootWindow(display);
575 XRRScreenResources* screen = GetScreenResourcesAndRecordUMA(display, window); 502 XRRScreenResources* screen = GetScreenResourcesAndRecordUMA(display, window);
576 CHECK(screen != NULL); 503 CHECK(screen != NULL);
577 504
578 // Detect our initial state. 505 // Detect our initial state.
579 OutputSnapshot outputs[2] = { {0}, {0} }; 506 OutputSnapshot outputs[2] = { {0}, {0} };
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
808 } 735 }
809 736
810 void OutputConfigurator::RemoveObserver(Observer* observer) { 737 void OutputConfigurator::RemoveObserver(Observer* observer) {
811 observers_.RemoveObserver(observer); 738 observers_.RemoveObserver(observer);
812 } 739 }
813 740
814 // static 741 // static
815 bool OutputConfigurator::IsInternalOutputName(const std::string& name) { 742 bool OutputConfigurator::IsInternalOutputName(const std::string& name) {
816 return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0; 743 return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0;
817 } 744 }
745 // static
746 bool OutputConfigurator::IsInternalOutput(const XRROutputInfo* output_info) {
747 return IsInternalOutputName(std::string(output_info->name));
748 }
749
750 // static
751 RRMode OutputConfigurator::GetOutputNativeMode(
752 const XRROutputInfo* output_info) {
753 if (output_info->nmode <= 0) {
754 return None;
755 }
oshima 2012/09/21 19:38:12 nuke {}
ynovikov 2012/09/21 23:05:36 Done.
756
757 return output_info->modes[0];
758 }
818 759
819 void OutputConfigurator::NotifyOnDisplayChanged() { 760 void OutputConfigurator::NotifyOnDisplayChanged() {
820 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged()); 761 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged());
821 } 762 }
822 763
764 bool OutputConfigurator::AddMirrorModeToInternalOutput(
765 Display* display,
766 XRRScreenResources* screen,
767 RROutput output_one,
768 RROutput output_two,
769 RRMode* output_one_mode,
770 RRMode* output_two_mode) {
771 // Add new mode only if panel fitting hardware will be able to display it.
772 if (!is_panel_fitting_enabled_) {
773 return false;
774 }
oshima 2012/09/21 19:38:12 nuke {}
ynovikov 2012/09/21 23:05:36 Done.
775
776 XRROutputInfo* output_one_info =
777 XRRGetOutputInfo(display, screen, output_one);
778 XRROutputInfo* output_two_info =
779 XRRGetOutputInfo(display, screen, output_two);
780 bool success = false;
781
782 // Both outputs should be connected in mirror mode
783 if (output_one_info->connection == RR_Connected &&
784 output_two_info->connection == RR_Connected) {
785 bool one_is_internal = IsInternalOutput(output_one_info);
786 bool two_is_internal = IsInternalOutput(output_two_info);
787
788 XRROutputInfo* internal_info = NULL;
789 XRROutputInfo* external_info = NULL;
790
791 if (one_is_internal) {
792 internal_info = output_one_info;
793 external_info = output_two_info;
794
795 VLOG_IF(1, two_is_internal) << "Two internal outputs detected.";
796 DCHECK(!two_is_internal);
797 } else if (two_is_internal) {
798 internal_info = output_two_info;
799 external_info = output_one_info;
800 }
801
802 bool internal_output_found = internal_info != NULL;
803
804 if (internal_output_found) {
805 RRMode internal_native_mode_id = GetOutputNativeMode(internal_info);
806 RRMode external_native_mode_id = GetOutputNativeMode(external_info);
807
808 if (internal_native_mode_id != None && external_native_mode_id != None) {
809 XRRModeInfo* internal_native_mode =
810 ModeInfoForID(screen, internal_native_mode_id);
811 XRRModeInfo* external_native_mode =
812 ModeInfoForID(screen, external_native_mode_id);
813
814 // Panel fitting will not work if the internal output maximal resolution
815 // is lower than that of the external output
816 if (internal_native_mode->width >= external_native_mode->width &&
817 internal_native_mode->height >= external_native_mode->height) {
818 XRRAddOutputMode(display, one_is_internal ? output_one : output_two,
819 external_native_mode_id);
820
821 *output_one_mode = *output_two_mode = external_native_mode_id;
822 success = true;
823 }
824 }
825 }
826 }
827
828 XRRFreeOutputInfo(output_one_info);
829 XRRFreeOutputInfo(output_two_info);
830
831 return success;
832 }
833
834 int OutputConfigurator::GetDualOutputs(Display* display,
cwolfe 2012/09/21 19:17:21 Just for my sanity, here's a diff -b between the v
ynovikov 2012/09/21 23:05:36 Done.
835 XRRScreenResources* screen,
836 OutputSnapshot* one,
837 OutputSnapshot* two) {
838 int found_count = 0;
839 XRROutputInfo* one_info = NULL;
840 XRROutputInfo* two_info = NULL;
841
842 for (int i = 0; (i < screen->noutput) && (found_count < 2); ++i) {
843 RROutput this_id = screen->outputs[i];
844 XRROutputInfo* output_info = XRRGetOutputInfo(display, screen, this_id);
845 bool is_connected = (RR_Connected == output_info->connection);
846
847 if (is_connected) {
848 OutputSnapshot *to_populate = NULL;
849
850 if (0 == found_count) {
851 to_populate = one;
852 one_info = output_info;
853 } else {
854 to_populate = two;
855 two_info = output_info;
856 }
857
858 to_populate->output = this_id;
859 // Now, look up the corresponding CRTC and any related info.
860 to_populate->crtc = output_info->crtc;
861 if (None != to_populate->crtc) {
862 XRRCrtcInfo* crtc_info =
863 XRRGetCrtcInfo(display, screen, to_populate->crtc);
864 to_populate->current_mode = crtc_info->mode;
865 to_populate->height = crtc_info->height;
866 to_populate->y = crtc_info->y;
867 XRRFreeCrtcInfo(crtc_info);
868 } else {
869 to_populate->current_mode = 0;
870 to_populate->height = 0;
871 to_populate->y = 0;
872 }
873 // Find the native_mode and leave the mirror_mode for the pass after the
874 // loop.
875 to_populate->native_mode = GetOutputNativeMode(output_info);
876 to_populate->mirror_mode = 0;
877
878 // See if this output refers to an internal display.
879 to_populate->is_internal = IsInternalOutput(output_info);
880
881 VLOG(1) << "Found display #" << found_count
882 << " with output " << (int)to_populate->output
883 << " crtc " << (int)to_populate->crtc
884 << " current mode " << (int)to_populate->current_mode;
885 ++found_count;
oshima 2012/09/21 19:38:12 you probably want to increment this before VLOG.
ynovikov 2012/09/21 23:05:36 I didn't change this code, just moved it. It does
886 } else {
887 XRRFreeOutputInfo(output_info);
888 }
889 }
890
891 if (2 == found_count) {
892 // Find the mirror modes (if there are any).
893 bool mirror_mode_found = FindMirrorModeForOutputs(display,
894 screen,
895 one->output,
896 two->output,
897 &one->mirror_mode,
898 &two->mirror_mode);
899 if (!mirror_mode_found) {
900 bool mirror_mode_added = AddMirrorModeToInternalOutput(display,
901 screen,
902 one->output,
903 two->output,
904 &one->mirror_mode,
905 &two->mirror_mode);
906 if (!mirror_mode_added) {
907 // We can't mirror so set mirror_mode to 0.
908 one->mirror_mode = 0;
909 two->mirror_mode = 0;
910 }
911 }
912 }
913
914 XRRFreeOutputInfo(one_info);
915 XRRFreeOutputInfo(two_info);
916 return found_count;
917 }
918
823 } // namespace chromeos 919 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698