| OLD | NEW |
| 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/Xrandr.h> | 8 #include <X11/extensions/Xrandr.h> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 | 116 |
| 117 OutputConfigurator::ModeInfo::ModeInfo(int width, | 117 OutputConfigurator::ModeInfo::ModeInfo(int width, |
| 118 int height, | 118 int height, |
| 119 bool interlaced, | 119 bool interlaced, |
| 120 float refresh_rate) | 120 float refresh_rate) |
| 121 : width(width), | 121 : width(width), |
| 122 height(height), | 122 height(height), |
| 123 interlaced(interlaced), | 123 interlaced(interlaced), |
| 124 refresh_rate(refresh_rate) {} | 124 refresh_rate(refresh_rate) {} |
| 125 | 125 |
| 126 OutputConfigurator::CoordinateTransformation::CoordinateTransformation() | |
| 127 : x_scale(1.0), | |
| 128 x_offset(0.0), | |
| 129 y_scale(1.0), | |
| 130 y_offset(0.0) {} | |
| 131 | |
| 132 OutputConfigurator::OutputSnapshot::OutputSnapshot() | 126 OutputConfigurator::OutputSnapshot::OutputSnapshot() |
| 133 : output(None), | 127 : output(None), |
| 134 crtc(None), | 128 crtc(None), |
| 135 current_mode(None), | 129 current_mode(None), |
| 136 native_mode(None), | 130 native_mode(None), |
| 137 mirror_mode(None), | 131 mirror_mode(None), |
| 138 selected_mode(None), | 132 selected_mode(None), |
| 139 x(0), | 133 x(0), |
| 140 y(0), | 134 y(0), |
| 141 width_mm(0), | 135 width_mm(0), |
| (...skipping 655 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 797 return false; | 791 return false; |
| 798 width = mode_info->width; | 792 width = mode_info->width; |
| 799 height = mode_info->height; | 793 height = mode_info->height; |
| 800 | 794 |
| 801 for (size_t i = 0; i < updated_outputs.size(); ++i) { | 795 for (size_t i = 0; i < updated_outputs.size(); ++i) { |
| 802 OutputSnapshot* output = &updated_outputs[i]; | 796 OutputSnapshot* output = &updated_outputs[i]; |
| 803 output->x = 0; | 797 output->x = 0; |
| 804 output->y = 0; | 798 output->y = 0; |
| 805 output->current_mode = output_power[i] ? output->mirror_mode : None; | 799 output->current_mode = output_power[i] ? output->mirror_mode : None; |
| 806 if (output->touch_device_id) { | 800 if (output->touch_device_id) { |
| 807 // CTM needs to be calculated if aspect preserving scaling is used. | |
| 808 // Otherwise, assume it is full screen, and use identity CTM. | |
| 809 if (output->mirror_mode != output->native_mode && | 801 if (output->mirror_mode != output->native_mode && |
| 810 output->is_aspect_preserving_scaling) { | 802 output->is_aspect_preserving_scaling) { |
| 811 output->transform = GetMirrorModeCTM(*output); | |
| 812 mirrored_display_area_ratio_map_[output->touch_device_id] = | 803 mirrored_display_area_ratio_map_[output->touch_device_id] = |
| 813 GetMirroredDisplayAreaRatio(*output); | 804 GetMirroredDisplayAreaRatio(*output); |
| 814 } | 805 } |
| 815 } | 806 } |
| 816 } | 807 } |
| 817 break; | 808 break; |
| 818 } | 809 } |
| 819 case ui::OUTPUT_STATE_DUAL_EXTENDED: { | 810 case ui::OUTPUT_STATE_DUAL_EXTENDED: { |
| 820 if (updated_outputs.size() != 2 || | 811 if (updated_outputs.size() != 2 || |
| 821 (num_on_outputs != 0 && num_on_outputs != 2)) { | 812 (num_on_outputs != 0 && num_on_outputs != 2)) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 834 // Retain the full screen size even if all outputs are off so the | 825 // Retain the full screen size even if all outputs are off so the |
| 835 // same desktop configuration can be restored when the outputs are | 826 // same desktop configuration can be restored when the outputs are |
| 836 // turned back on. | 827 // turned back on. |
| 837 const ModeInfo* mode_info = | 828 const ModeInfo* mode_info = |
| 838 GetModeInfo(updated_outputs[i], updated_outputs[i].selected_mode); | 829 GetModeInfo(updated_outputs[i], updated_outputs[i].selected_mode); |
| 839 if (!mode_info) | 830 if (!mode_info) |
| 840 return false; | 831 return false; |
| 841 width = std::max<int>(width, mode_info->width); | 832 width = std::max<int>(width, mode_info->width); |
| 842 height += (height ? kVerticalGap : 0) + mode_info->height; | 833 height += (height ? kVerticalGap : 0) + mode_info->height; |
| 843 } | 834 } |
| 844 | |
| 845 for (size_t i = 0; i < updated_outputs.size(); ++i) { | |
| 846 OutputSnapshot* output = &updated_outputs[i]; | |
| 847 if (output->touch_device_id) | |
| 848 output->transform = GetExtendedModeCTM(*output, width, height); | |
| 849 } | |
| 850 break; | 835 break; |
| 851 } | 836 } |
| 852 } | 837 } |
| 853 | 838 |
| 854 // Finally, apply the desired changes. | 839 // Finally, apply the desired changes. |
| 855 DCHECK_EQ(cached_outputs_.size(), updated_outputs.size()); | 840 DCHECK_EQ(cached_outputs_.size(), updated_outputs.size()); |
| 856 bool all_succeeded = true; | 841 bool all_succeeded = true; |
| 857 if (!updated_outputs.empty()) { | 842 if (!updated_outputs.empty()) { |
| 858 native_display_delegate_->CreateFrameBuffer(width, height, updated_outputs); | 843 native_display_delegate_->CreateFrameBuffer(width, height, updated_outputs); |
| 859 for (size_t i = 0; i < updated_outputs.size(); ++i) { | 844 for (size_t i = 0; i < updated_outputs.size(); ++i) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 892 updated_outputs[i].current_mode = it->first; | 877 updated_outputs[i].current_mode = it->first; |
| 893 best_mode_pixels = pixel_count; | 878 best_mode_pixels = pixel_count; |
| 894 } | 879 } |
| 895 } | 880 } |
| 896 | 881 |
| 897 if (best_mode_pixels == 0) | 882 if (best_mode_pixels == 0) |
| 898 break; | 883 break; |
| 899 } | 884 } |
| 900 | 885 |
| 901 if (configure_succeeded) { | 886 if (configure_succeeded) { |
| 902 if (output.touch_device_id) | |
| 903 touchscreen_delegate_->ConfigureCTM(output.touch_device_id, | |
| 904 output.transform); | |
| 905 cached_outputs_[i] = updated_outputs[i]; | 887 cached_outputs_[i] = updated_outputs[i]; |
| 906 } else { | 888 } else { |
| 907 all_succeeded = false; | 889 all_succeeded = false; |
| 908 } | 890 } |
| 909 | 891 |
| 910 // If we are trying to set mirror mode and one of the modesets fails, | 892 // If we are trying to set mirror mode and one of the modesets fails, |
| 911 // then the two monitors will be mis-matched. In this case, return | 893 // then the two monitors will be mis-matched. In this case, return |
| 912 // false to let the observers be aware. | 894 // false to let the observers be aware. |
| 913 if (output_state == ui::OUTPUT_STATE_DUAL_MIRROR && output_power[i] && | 895 if (output_state == ui::OUTPUT_STATE_DUAL_MIRROR && output_power[i] && |
| 914 output.current_mode != output.mirror_mode) | 896 output.current_mode != output.mirror_mode) |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 949 } | 931 } |
| 950 return state_controller_->GetStateForDisplayIds(display_ids); | 932 return state_controller_->GetStateForDisplayIds(display_ids); |
| 951 } | 933 } |
| 952 } | 934 } |
| 953 default: | 935 default: |
| 954 NOTREACHED(); | 936 NOTREACHED(); |
| 955 } | 937 } |
| 956 return ui::OUTPUT_STATE_INVALID; | 938 return ui::OUTPUT_STATE_INVALID; |
| 957 } | 939 } |
| 958 | 940 |
| 959 OutputConfigurator::CoordinateTransformation | |
| 960 OutputConfigurator::GetMirrorModeCTM( | |
| 961 const OutputConfigurator::OutputSnapshot& output) { | |
| 962 CoordinateTransformation ctm; // Default to identity | |
| 963 const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); | |
| 964 const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); | |
| 965 | |
| 966 if (!native_mode_info || !mirror_mode_info || | |
| 967 native_mode_info->height == 0 || mirror_mode_info->height == 0 || | |
| 968 native_mode_info->width == 0 || mirror_mode_info->width == 0) | |
| 969 return ctm; | |
| 970 | |
| 971 float native_mode_ar = static_cast<float>(native_mode_info->width) / | |
| 972 static_cast<float>(native_mode_info->height); | |
| 973 float mirror_mode_ar = static_cast<float>(mirror_mode_info->width) / | |
| 974 static_cast<float>(mirror_mode_info->height); | |
| 975 | |
| 976 if (mirror_mode_ar > native_mode_ar) { // Letterboxing | |
| 977 ctm.x_scale = 1.0; | |
| 978 ctm.x_offset = 0.0; | |
| 979 ctm.y_scale = mirror_mode_ar / native_mode_ar; | |
| 980 ctm.y_offset = (native_mode_ar / mirror_mode_ar - 1.0) * 0.5; | |
| 981 return ctm; | |
| 982 } | |
| 983 if (native_mode_ar > mirror_mode_ar) { // Pillarboxing | |
| 984 ctm.y_scale = 1.0; | |
| 985 ctm.y_offset = 0.0; | |
| 986 ctm.x_scale = native_mode_ar / mirror_mode_ar; | |
| 987 ctm.x_offset = (mirror_mode_ar / native_mode_ar - 1.0) * 0.5; | |
| 988 return ctm; | |
| 989 } | |
| 990 | |
| 991 return ctm; // Same aspect ratio - return identity | |
| 992 } | |
| 993 | |
| 994 OutputConfigurator::CoordinateTransformation | |
| 995 OutputConfigurator::GetExtendedModeCTM( | |
| 996 const OutputConfigurator::OutputSnapshot& output, | |
| 997 int framebuffer_width, | |
| 998 int framebuffer_height) { | |
| 999 CoordinateTransformation ctm; // Default to identity | |
| 1000 const ModeInfo* mode_info = GetModeInfo(output, output.selected_mode); | |
| 1001 DCHECK(mode_info); | |
| 1002 if (!mode_info) | |
| 1003 return ctm; | |
| 1004 // An example of how to calculate the CTM. | |
| 1005 // Suppose we have 2 monitors, the first one has size 1366 x 768. | |
| 1006 // The second one has size 2560 x 1600 | |
| 1007 // The total size of framebuffer is 2560 x 2428 | |
| 1008 // where 2428 = 768 + 60 (hidden gap) + 1600 | |
| 1009 // and the sceond monitor is translated to Point (0, 828) in the | |
| 1010 // framebuffer. | |
| 1011 // X will first map input event location to [0, 2560) x [0, 2428), | |
| 1012 // then apply CTM on it. | |
| 1013 // So to compute CTM, for monitor1, we have | |
| 1014 // x_scale = (1366 - 1) / (2560 - 1) | |
| 1015 // x_offset = 0 / (2560 - 1) | |
| 1016 // y_scale = (768 - 1) / (2428 - 1) | |
| 1017 // y_offset = 0 / (2428 -1) | |
| 1018 // For Monitor 2, we have | |
| 1019 // x_scale = (2560 - 1) / (2560 - 1) | |
| 1020 // x_offset = 0 / (2560 - 1) | |
| 1021 // y_scale = (1600 - 1) / (2428 - 1) | |
| 1022 // y_offset = 828 / (2428 -1) | |
| 1023 // See the unittest OutputConfiguratorTest.CTMForMultiScreens. | |
| 1024 ctm.x_scale = | |
| 1025 static_cast<float>(mode_info->width - 1) / (framebuffer_width - 1); | |
| 1026 ctm.x_offset = static_cast<float>(output.x) / (framebuffer_width - 1); | |
| 1027 ctm.y_scale = | |
| 1028 static_cast<float>(mode_info->height - 1) / (framebuffer_height - 1); | |
| 1029 ctm.y_offset = static_cast<float>(output.y) / (framebuffer_height - 1); | |
| 1030 return ctm; | |
| 1031 } | |
| 1032 | |
| 1033 float OutputConfigurator::GetMirroredDisplayAreaRatio( | 941 float OutputConfigurator::GetMirroredDisplayAreaRatio( |
| 1034 const OutputConfigurator::OutputSnapshot& output) { | 942 const OutputConfigurator::OutputSnapshot& output) { |
| 1035 float area_ratio = 1.0f; | 943 float area_ratio = 1.0f; |
| 1036 const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); | 944 const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); |
| 1037 const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); | 945 const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); |
| 1038 | 946 |
| 1039 if (!native_mode_info || !mirror_mode_info || | 947 if (!native_mode_info || !mirror_mode_info || |
| 1040 native_mode_info->height == 0 || mirror_mode_info->height == 0 || | 948 native_mode_info->height == 0 || mirror_mode_info->height == 0 || |
| 1041 native_mode_info->width == 0 || mirror_mode_info->width == 0) | 949 native_mode_info->width == 0 || mirror_mode_info->width == 0) |
| 1042 return area_ratio; | 950 return area_ratio; |
| 1043 | 951 |
| 1044 float width_ratio = static_cast<float>(mirror_mode_info->width) / | 952 float width_ratio = static_cast<float>(mirror_mode_info->width) / |
| 1045 static_cast<float>(native_mode_info->width); | 953 static_cast<float>(native_mode_info->width); |
| 1046 float height_ratio = static_cast<float>(mirror_mode_info->height) / | 954 float height_ratio = static_cast<float>(mirror_mode_info->height) / |
| 1047 static_cast<float>(native_mode_info->height); | 955 static_cast<float>(native_mode_info->height); |
| 1048 | 956 |
| 1049 area_ratio = width_ratio * height_ratio; | 957 area_ratio = width_ratio * height_ratio; |
| 1050 return area_ratio; | 958 return area_ratio; |
| 1051 } | 959 } |
| 1052 | 960 |
| 1053 } // namespace chromeos | 961 } // namespace chromeos |
| OLD | NEW |