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

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: Fix compilation on non-Chrome OS Created 8 years, 2 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
« no previous file with comments | « chromeos/display/output_configurator.h ('k') | content/browser/gpu/gpu_blacklist.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
(...skipping 10 matching lines...) Expand all
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 "base/time.h" 25 #include "base/time.h"
26 #include "chromeos/dbus/dbus_thread_manager.h" 26 #include "chromeos/dbus/dbus_thread_manager.h"
27 #include "chromeos/dbus/power_manager_client.h" 27 #include "chromeos/dbus/power_manager_client.h"
28 28
29 namespace chromeos { 29 namespace chromeos {
30 30
31 struct OutputSnapshot {
32 RROutput output;
33 RRCrtc crtc;
34 RRMode current_mode;
35 int height;
36 int y;
37 RRMode native_mode;
38 RRMode mirror_mode;
39 bool is_internal;
40 };
41
31 namespace { 42 namespace {
32 // DPI measurements. 43 // DPI measurements.
33 const float kMmInInch = 25.4; 44 const float kMmInInch = 25.4;
34 const float kDpi96 = 96.0; 45 const float kDpi96 = 96.0;
35 const float kPixelsToMmScale = kMmInInch / kDpi96; 46 const float kPixelsToMmScale = kMmInInch / kDpi96;
36 47
37 // The DPI threshold to detech high density screen. 48 // The DPI threshold to detech high density screen.
38 // Higher DPI than this will use device_scale_factor=2 49 // Higher DPI than this will use device_scale_factor=2
39 // Should be kept in sync with display_change_observer_x11.cc 50 // Should be kept in sync with display_change_observer_x11.cc
40 const unsigned int kHighDensityDIPThreshold = 160; 51 const unsigned int kHighDensityDIPThreshold = 160;
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 x, 202 x,
192 y, 203 y,
193 kMode, 204 kMode,
194 kOutput); 205 kOutput);
195 } 206 }
196 int mm_width = width * kPixelsToMmScale; 207 int mm_width = width * kPixelsToMmScale;
197 int mm_height = height * kPixelsToMmScale; 208 int mm_height = height * kPixelsToMmScale;
198 XRRSetScreenSize(display, window, width, height, mm_width, mm_height); 209 XRRSetScreenSize(display, window, width, height, mm_width, mm_height);
199 } 210 }
200 211
201 typedef struct OutputSnapshot {
202 RROutput output;
203 RRCrtc crtc;
204 RRMode current_mode;
205 int height;
206 int y;
207 RRMode native_mode;
208 RRMode mirror_mode;
209 bool is_internal;
210 } OutputSnapshot;
211
212 static int GetDualOutputs(Display* display,
213 XRRScreenResources* screen,
214 OutputSnapshot* one,
215 OutputSnapshot* two) {
216 int found_count = 0;
217 XRROutputInfo* one_info = NULL;
218 XRROutputInfo* two_info = NULL;
219
220 for (int i = 0; (i < screen->noutput) && (found_count < 2); ++i) {
221 RROutput this_id = screen->outputs[i];
222 XRROutputInfo* output_info = XRRGetOutputInfo(display, screen, this_id);
223 bool is_connected = (RR_Connected == output_info->connection);
224
225 if (is_connected) {
226 OutputSnapshot *to_populate = NULL;
227
228 if (0 == found_count) {
229 to_populate = one;
230 one_info = output_info;
231 } else {
232 to_populate = two;
233 two_info = output_info;
234 }
235
236 to_populate->output = this_id;
237 // Now, look up the corresponding CRTC and any related info.
238 to_populate->crtc = output_info->crtc;
239 if (None != to_populate->crtc) {
240 XRRCrtcInfo* crtc_info =
241 XRRGetCrtcInfo(display, screen, to_populate->crtc);
242 to_populate->current_mode = crtc_info->mode;
243 to_populate->height = crtc_info->height;
244 to_populate->y = crtc_info->y;
245 XRRFreeCrtcInfo(crtc_info);
246 } else {
247 to_populate->current_mode = 0;
248 to_populate->height = 0;
249 to_populate->y = 0;
250 }
251 // Find the native_mode and leave the mirror_mode for the pass after the
252 // loop.
253 if (output_info->nmode > 0)
254 to_populate->native_mode = output_info->modes[0];
255 to_populate->mirror_mode = 0;
256
257 // See if this output refers to an internal display.
258 to_populate->is_internal =
259 OutputConfigurator::IsInternalOutputName(
260 std::string(output_info->name));
261
262 VLOG(1) << "Found display #" << found_count
263 << " with output " << (int)to_populate->output
264 << " crtc " << (int)to_populate->crtc
265 << " current mode " << (int)to_populate->current_mode;
266 ++found_count;
267 } else {
268 XRRFreeOutputInfo(output_info);
269 }
270 }
271
272 if (2 == found_count) {
273 // Find the mirror modes (if there are any).
274 bool can_mirror = FindMirrorModeForOutputs(display,
275 screen,
276 one->output,
277 two->output,
278 &one->mirror_mode,
279 &two->mirror_mode);
280 if (!can_mirror) {
281 // We can't mirror so set mirror_mode to 0.
282 one->mirror_mode = 0;
283 two->mirror_mode = 0;
284 }
285 }
286
287 XRRFreeOutputInfo(one_info);
288 XRRFreeOutputInfo(two_info);
289 return found_count;
290 }
291
292 static OutputState InferCurrentState(Display* display, 212 static OutputState InferCurrentState(Display* display,
293 XRRScreenResources* screen, 213 XRRScreenResources* screen,
294 const OutputSnapshot* outputs, 214 const OutputSnapshot* outputs,
295 int output_count) { 215 int output_count) {
296 OutputState state = STATE_INVALID; 216 OutputState state = STATE_INVALID;
297 switch (output_count) { 217 switch (output_count) {
298 case 0: 218 case 0:
299 state = STATE_HEADLESS; 219 state = STATE_HEADLESS;
300 break; 220 break;
301 case 1: 221 case 1:
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 479
560 // "Projecting" is defined as having more than 1 output connected while at 480 // "Projecting" is defined as having more than 1 output connected while at
561 // least one of them is an internal output. 481 // least one of them is an internal output.
562 return has_internal_output && (connected_output_count > 1); 482 return has_internal_output && (connected_output_count > 1);
563 } 483 }
564 484
565 } // namespace 485 } // namespace
566 486
567 OutputConfigurator::OutputConfigurator() 487 OutputConfigurator::OutputConfigurator()
568 : is_running_on_chrome_os_(base::chromeos::IsRunningOnChromeOS()), 488 : is_running_on_chrome_os_(base::chromeos::IsRunningOnChromeOS()),
489 is_panel_fitting_enabled_(false),
490 connected_output_count_(0),
569 xrandr_event_base_(0), 491 xrandr_event_base_(0),
570 output_state_(STATE_INVALID) { 492 output_state_(STATE_INVALID) {
493 }
494
495 void OutputConfigurator::Init(bool is_panel_fitting_enabled) {
571 if (!is_running_on_chrome_os_) 496 if (!is_running_on_chrome_os_)
572 return; 497 return;
573 498
499 is_panel_fitting_enabled_ = is_panel_fitting_enabled;
500
574 // Cache the initial output state. 501 // Cache the initial output state.
575 Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay(); 502 Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
576 CHECK(display != NULL); 503 CHECK(display != NULL);
577 XGrabServer(display); 504 XGrabServer(display);
578 Window window = DefaultRootWindow(display); 505 Window window = DefaultRootWindow(display);
579 XRRScreenResources* screen = GetScreenResourcesAndRecordUMA(display, window); 506 XRRScreenResources* screen = GetScreenResourcesAndRecordUMA(display, window);
580 CHECK(screen != NULL); 507 CHECK(screen != NULL);
581 508
582 // Detect our initial state. 509 // Detect our initial state.
583 OutputSnapshot outputs[2] = { {0}, {0} }; 510 OutputSnapshot outputs[2] = { {0}, {0} };
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
844 // static 771 // static
845 bool OutputConfigurator::IsInternalOutputName(const std::string& name) { 772 bool OutputConfigurator::IsInternalOutputName(const std::string& name) {
846 return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0; 773 return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0;
847 } 774 }
848 775
849 void OutputConfigurator::NotifyOnDisplayChanged() { 776 void OutputConfigurator::NotifyOnDisplayChanged() {
850 notification_timer_.reset(); 777 notification_timer_.reset();
851 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged()); 778 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged());
852 } 779 }
853 780
781 int OutputConfigurator::GetDualOutputs(Display* display,
782 XRRScreenResources* screen,
783 OutputSnapshot* one,
784 OutputSnapshot* two) {
785 int found_count = 0;
786 XRROutputInfo* one_info = NULL;
787 XRROutputInfo* two_info = NULL;
788
789 for (int i = 0; (i < screen->noutput) && (found_count < 2); ++i) {
790 RROutput this_id = screen->outputs[i];
791 XRROutputInfo* output_info = XRRGetOutputInfo(display, screen, this_id);
792 bool is_connected = (RR_Connected == output_info->connection);
793
794 if (is_connected) {
795 OutputSnapshot *to_populate = NULL;
796
797 if (0 == found_count) {
798 to_populate = one;
799 one_info = output_info;
800 } else {
801 to_populate = two;
802 two_info = output_info;
803 }
804
805 to_populate->output = this_id;
806 // Now, look up the corresponding CRTC and any related info.
807 to_populate->crtc = output_info->crtc;
808 if (None != to_populate->crtc) {
809 XRRCrtcInfo* crtc_info =
810 XRRGetCrtcInfo(display, screen, to_populate->crtc);
811 to_populate->current_mode = crtc_info->mode;
812 to_populate->height = crtc_info->height;
813 to_populate->y = crtc_info->y;
814 XRRFreeCrtcInfo(crtc_info);
815 } else {
816 to_populate->current_mode = 0;
817 to_populate->height = 0;
818 to_populate->y = 0;
819 }
820 // Find the native_mode and leave the mirror_mode for the pass after the
821 // loop.
822 to_populate->native_mode = GetOutputNativeMode(output_info);
823 to_populate->mirror_mode = 0;
824
825 // See if this output refers to an internal display.
826 to_populate->is_internal = IsInternalOutput(output_info);
827
828 VLOG(1) << "Found display #" << found_count
829 << " with output " << (int)to_populate->output
830 << " crtc " << (int)to_populate->crtc
831 << " current mode " << (int)to_populate->current_mode;
832 ++found_count;
833 } else {
834 XRRFreeOutputInfo(output_info);
835 }
836 }
837
838 if (2 == found_count) {
839 // Find the mirror modes (if there are any).
840 bool mirror_mode_found = FindMirrorModeForOutputs(display,
841 screen,
842 one->output,
843 two->output,
844 &one->mirror_mode,
845 &two->mirror_mode);
846 if (!mirror_mode_found) {
847 bool mirror_mode_added = AddMirrorModeToInternalOutput(display,
848 screen,
849 one->output,
850 two->output,
851 &one->mirror_mode,
852 &two->mirror_mode);
853 if (!mirror_mode_added) {
854 // We can't mirror so set mirror_mode to 0.
855 one->mirror_mode = 0;
856 two->mirror_mode = 0;
857 }
858 }
859 }
860
861 XRRFreeOutputInfo(one_info);
862 XRRFreeOutputInfo(two_info);
863 return found_count;
864 }
865
866 bool OutputConfigurator::AddMirrorModeToInternalOutput(
867 Display* display,
868 XRRScreenResources* screen,
869 RROutput output_one,
870 RROutput output_two,
871 RRMode* output_one_mode,
872 RRMode* output_two_mode) {
873 // Add new mode only if panel fitting hardware will be able to display it.
874 if (!is_panel_fitting_enabled_)
875 return false;
876
877 XRROutputInfo* output_one_info =
878 XRRGetOutputInfo(display, screen, output_one);
879 XRROutputInfo* output_two_info =
880 XRRGetOutputInfo(display, screen, output_two);
881 bool success = false;
882
883 // Both outputs should be connected in mirror mode
884 if (output_one_info->connection == RR_Connected &&
885 output_two_info->connection == RR_Connected) {
886 bool one_is_internal = IsInternalOutput(output_one_info);
887 bool two_is_internal = IsInternalOutput(output_two_info);
888
889 XRROutputInfo* internal_info = NULL;
890 XRROutputInfo* external_info = NULL;
891
892 if (one_is_internal) {
893 internal_info = output_one_info;
894 external_info = output_two_info;
895
896 VLOG_IF(1, two_is_internal) << "Two internal outputs detected.";
897 DCHECK(!two_is_internal);
898 } else if (two_is_internal) {
899 internal_info = output_two_info;
900 external_info = output_one_info;
901 }
902
903 bool internal_output_found = internal_info != NULL;
904
905 if (internal_output_found) {
906 RRMode internal_native_mode_id = GetOutputNativeMode(internal_info);
907 RRMode external_native_mode_id = GetOutputNativeMode(external_info);
908
909 if (internal_native_mode_id != None && external_native_mode_id != None) {
910 XRRModeInfo* internal_native_mode =
911 ModeInfoForID(screen, internal_native_mode_id);
912 XRRModeInfo* external_native_mode =
913 ModeInfoForID(screen, external_native_mode_id);
914
915 // Panel fitting will not work if the internal output maximal resolution
916 // is lower than that of the external output
917 if (internal_native_mode->width >= external_native_mode->width &&
918 internal_native_mode->height >= external_native_mode->height) {
919 XRRAddOutputMode(display, one_is_internal ? output_one : output_two,
920 external_native_mode_id);
921
922 *output_one_mode = *output_two_mode = external_native_mode_id;
923 success = true;
924 }
925 }
926 }
927 }
928
929 XRRFreeOutputInfo(output_one_info);
930 XRRFreeOutputInfo(output_two_info);
931
932 return success;
933 }
934
935 // static
936 bool OutputConfigurator::IsInternalOutput(const XRROutputInfo* output_info) {
937 return IsInternalOutputName(std::string(output_info->name));
938 }
939
940 // static
941 RRMode OutputConfigurator::GetOutputNativeMode(
942 const XRROutputInfo* output_info) {
943 if (output_info->nmode <= 0)
944 return None;
945
946 return output_info->modes[0];
947 }
948
854 } // namespace chromeos 949 } // namespace chromeos
OLDNEW
« no previous file with comments | « chromeos/display/output_configurator.h ('k') | content/browser/gpu/gpu_blacklist.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698