| 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 #include <X11/extensions/XInput2.h> | 9 #include <X11/extensions/XInput2.h> |
| 10 | 10 |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 | 117 |
| 118 OutputConfigurator::ModeInfo::ModeInfo(int width, | 118 OutputConfigurator::ModeInfo::ModeInfo(int width, |
| 119 int height, | 119 int height, |
| 120 bool interlaced, | 120 bool interlaced, |
| 121 float refresh_rate) | 121 float refresh_rate) |
| 122 : width(width), | 122 : width(width), |
| 123 height(height), | 123 height(height), |
| 124 interlaced(interlaced), | 124 interlaced(interlaced), |
| 125 refresh_rate(refresh_rate) {} | 125 refresh_rate(refresh_rate) {} |
| 126 | 126 |
| 127 OutputConfigurator::CoordinateTransformation::CoordinateTransformation() | |
| 128 : x_scale(1.0), | |
| 129 x_offset(0.0), | |
| 130 y_scale(1.0), | |
| 131 y_offset(0.0) {} | |
| 132 | |
| 133 OutputConfigurator::OutputSnapshot::OutputSnapshot() | 127 OutputConfigurator::OutputSnapshot::OutputSnapshot() |
| 134 : output(None), | 128 : output(None), |
| 135 crtc(None), | 129 crtc(None), |
| 136 current_mode(None), | 130 current_mode(None), |
| 137 native_mode(None), | 131 native_mode(None), |
| 138 mirror_mode(None), | 132 mirror_mode(None), |
| 139 selected_mode(None), | 133 selected_mode(None), |
| 140 x(0), | 134 x(0), |
| 141 y(0), | 135 y(0), |
| 142 width_mm(0), | 136 width_mm(0), |
| (...skipping 737 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 880 return false; | 874 return false; |
| 881 width = mode_info->width; | 875 width = mode_info->width; |
| 882 height = mode_info->height; | 876 height = mode_info->height; |
| 883 | 877 |
| 884 for (size_t i = 0; i < updated_outputs.size(); ++i) { | 878 for (size_t i = 0; i < updated_outputs.size(); ++i) { |
| 885 OutputSnapshot* output = &updated_outputs[i]; | 879 OutputSnapshot* output = &updated_outputs[i]; |
| 886 output->x = 0; | 880 output->x = 0; |
| 887 output->y = 0; | 881 output->y = 0; |
| 888 output->current_mode = output_power[i] ? output->mirror_mode : None; | 882 output->current_mode = output_power[i] ? output->mirror_mode : None; |
| 889 if (output->touch_device_id) { | 883 if (output->touch_device_id) { |
| 890 // CTM needs to be calculated if aspect preserving scaling is used. | |
| 891 // Otherwise, assume it is full screen, and use identity CTM. | |
| 892 if (output->mirror_mode != output->native_mode && | 884 if (output->mirror_mode != output->native_mode && |
| 893 output->is_aspect_preserving_scaling) { | 885 output->is_aspect_preserving_scaling) { |
| 894 output->transform = GetMirrorModeCTM(*output); | |
| 895 mirrored_display_area_ratio_map_[output->touch_device_id] = | 886 mirrored_display_area_ratio_map_[output->touch_device_id] = |
| 896 GetMirroredDisplayAreaRatio(*output); | 887 GetMirroredDisplayAreaRatio(*output); |
| 897 } | 888 } |
| 898 } | 889 } |
| 899 } | 890 } |
| 900 break; | 891 break; |
| 901 } | 892 } |
| 902 case ui::OUTPUT_STATE_DUAL_EXTENDED: { | 893 case ui::OUTPUT_STATE_DUAL_EXTENDED: { |
| 903 if (updated_outputs.size() != 2 || | 894 if (updated_outputs.size() != 2 || |
| 904 (num_on_outputs != 0 && num_on_outputs != 2)) { | 895 (num_on_outputs != 0 && num_on_outputs != 2)) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 917 // Retain the full screen size even if all outputs are off so the | 908 // Retain the full screen size even if all outputs are off so the |
| 918 // same desktop configuration can be restored when the outputs are | 909 // same desktop configuration can be restored when the outputs are |
| 919 // turned back on. | 910 // turned back on. |
| 920 const ModeInfo* mode_info = | 911 const ModeInfo* mode_info = |
| 921 GetModeInfo(updated_outputs[i], updated_outputs[i].selected_mode); | 912 GetModeInfo(updated_outputs[i], updated_outputs[i].selected_mode); |
| 922 if (!mode_info) | 913 if (!mode_info) |
| 923 return false; | 914 return false; |
| 924 width = std::max<int>(width, mode_info->width); | 915 width = std::max<int>(width, mode_info->width); |
| 925 height += (height ? kVerticalGap : 0) + mode_info->height; | 916 height += (height ? kVerticalGap : 0) + mode_info->height; |
| 926 } | 917 } |
| 927 | |
| 928 for (size_t i = 0; i < updated_outputs.size(); ++i) { | |
| 929 OutputSnapshot* output = &updated_outputs[i]; | |
| 930 if (output->touch_device_id) | |
| 931 output->transform = GetExtendedModeCTM(*output, width, height); | |
| 932 } | |
| 933 break; | 918 break; |
| 934 } | 919 } |
| 935 } | 920 } |
| 936 | 921 |
| 937 // Finally, apply the desired changes. | 922 // Finally, apply the desired changes. |
| 938 DCHECK_EQ(cached_outputs_.size(), updated_outputs.size()); | 923 DCHECK_EQ(cached_outputs_.size(), updated_outputs.size()); |
| 939 bool all_succeeded = true; | 924 bool all_succeeded = true; |
| 940 if (!updated_outputs.empty()) { | 925 if (!updated_outputs.empty()) { |
| 941 native_display_delegate_->CreateFrameBuffer(width, height, updated_outputs); | 926 native_display_delegate_->CreateFrameBuffer(width, height, updated_outputs); |
| 942 for (size_t i = 0; i < updated_outputs.size(); ++i) { | 927 for (size_t i = 0; i < updated_outputs.size(); ++i) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 976 updated_outputs[i].current_mode = it->first; | 961 updated_outputs[i].current_mode = it->first; |
| 977 best_mode_pixels = pixel_count; | 962 best_mode_pixels = pixel_count; |
| 978 } | 963 } |
| 979 } | 964 } |
| 980 | 965 |
| 981 if (best_mode_pixels == 0) | 966 if (best_mode_pixels == 0) |
| 982 break; | 967 break; |
| 983 } | 968 } |
| 984 | 969 |
| 985 if (configure_succeeded) { | 970 if (configure_succeeded) { |
| 986 if (output.touch_device_id) | |
| 987 touchscreen_delegate_->ConfigureCTM(output.touch_device_id, | |
| 988 output.transform); | |
| 989 cached_outputs_[i] = updated_outputs[i]; | 971 cached_outputs_[i] = updated_outputs[i]; |
| 990 } else { | 972 } else { |
| 991 all_succeeded = false; | 973 all_succeeded = false; |
| 992 } | 974 } |
| 993 | 975 |
| 994 // If we are trying to set mirror mode and one of the modesets fails, | 976 // If we are trying to set mirror mode and one of the modesets fails, |
| 995 // then the two monitors will be mis-matched. In this case, return | 977 // then the two monitors will be mis-matched. In this case, return |
| 996 // false to let the observers be aware. | 978 // false to let the observers be aware. |
| 997 if (output_state == ui::OUTPUT_STATE_DUAL_MIRROR && output_power[i] && | 979 if (output_state == ui::OUTPUT_STATE_DUAL_MIRROR && output_power[i] && |
| 998 output.current_mode != output.mirror_mode) | 980 output.current_mode != output.mirror_mode) |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1033 } | 1015 } |
| 1034 return state_controller_->GetStateForDisplayIds(display_ids); | 1016 return state_controller_->GetStateForDisplayIds(display_ids); |
| 1035 } | 1017 } |
| 1036 } | 1018 } |
| 1037 default: | 1019 default: |
| 1038 NOTREACHED(); | 1020 NOTREACHED(); |
| 1039 } | 1021 } |
| 1040 return ui::OUTPUT_STATE_INVALID; | 1022 return ui::OUTPUT_STATE_INVALID; |
| 1041 } | 1023 } |
| 1042 | 1024 |
| 1043 OutputConfigurator::CoordinateTransformation | |
| 1044 OutputConfigurator::GetMirrorModeCTM( | |
| 1045 const OutputConfigurator::OutputSnapshot& output) { | |
| 1046 CoordinateTransformation ctm; // Default to identity | |
| 1047 const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); | |
| 1048 const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); | |
| 1049 | |
| 1050 if (!native_mode_info || !mirror_mode_info || | |
| 1051 native_mode_info->height == 0 || mirror_mode_info->height == 0 || | |
| 1052 native_mode_info->width == 0 || mirror_mode_info->width == 0) | |
| 1053 return ctm; | |
| 1054 | |
| 1055 float native_mode_ar = static_cast<float>(native_mode_info->width) / | |
| 1056 static_cast<float>(native_mode_info->height); | |
| 1057 float mirror_mode_ar = static_cast<float>(mirror_mode_info->width) / | |
| 1058 static_cast<float>(mirror_mode_info->height); | |
| 1059 | |
| 1060 if (mirror_mode_ar > native_mode_ar) { // Letterboxing | |
| 1061 ctm.x_scale = 1.0; | |
| 1062 ctm.x_offset = 0.0; | |
| 1063 ctm.y_scale = mirror_mode_ar / native_mode_ar; | |
| 1064 ctm.y_offset = (native_mode_ar / mirror_mode_ar - 1.0) * 0.5; | |
| 1065 return ctm; | |
| 1066 } | |
| 1067 if (native_mode_ar > mirror_mode_ar) { // Pillarboxing | |
| 1068 ctm.y_scale = 1.0; | |
| 1069 ctm.y_offset = 0.0; | |
| 1070 ctm.x_scale = native_mode_ar / mirror_mode_ar; | |
| 1071 ctm.x_offset = (mirror_mode_ar / native_mode_ar - 1.0) * 0.5; | |
| 1072 return ctm; | |
| 1073 } | |
| 1074 | |
| 1075 return ctm; // Same aspect ratio - return identity | |
| 1076 } | |
| 1077 | |
| 1078 OutputConfigurator::CoordinateTransformation | |
| 1079 OutputConfigurator::GetExtendedModeCTM( | |
| 1080 const OutputConfigurator::OutputSnapshot& output, | |
| 1081 int framebuffer_width, | |
| 1082 int framebuffer_height) { | |
| 1083 CoordinateTransformation ctm; // Default to identity | |
| 1084 const ModeInfo* mode_info = GetModeInfo(output, output.selected_mode); | |
| 1085 DCHECK(mode_info); | |
| 1086 if (!mode_info) | |
| 1087 return ctm; | |
| 1088 // An example of how to calculate the CTM. | |
| 1089 // Suppose we have 2 monitors, the first one has size 1366 x 768. | |
| 1090 // The second one has size 2560 x 1600 | |
| 1091 // The total size of framebuffer is 2560 x 2428 | |
| 1092 // where 2428 = 768 + 60 (hidden gap) + 1600 | |
| 1093 // and the sceond monitor is translated to Point (0, 828) in the | |
| 1094 // framebuffer. | |
| 1095 // X will first map input event location to [0, 2560) x [0, 2428), | |
| 1096 // then apply CTM on it. | |
| 1097 // So to compute CTM, for monitor1, we have | |
| 1098 // x_scale = (1366 - 1) / (2560 - 1) | |
| 1099 // x_offset = 0 / (2560 - 1) | |
| 1100 // y_scale = (768 - 1) / (2428 - 1) | |
| 1101 // y_offset = 0 / (2428 -1) | |
| 1102 // For Monitor 2, we have | |
| 1103 // x_scale = (2560 - 1) / (2560 - 1) | |
| 1104 // x_offset = 0 / (2560 - 1) | |
| 1105 // y_scale = (1600 - 1) / (2428 - 1) | |
| 1106 // y_offset = 828 / (2428 -1) | |
| 1107 // See the unittest OutputConfiguratorTest.CTMForMultiScreens. | |
| 1108 ctm.x_scale = | |
| 1109 static_cast<float>(mode_info->width - 1) / (framebuffer_width - 1); | |
| 1110 ctm.x_offset = static_cast<float>(output.x) / (framebuffer_width - 1); | |
| 1111 ctm.y_scale = | |
| 1112 static_cast<float>(mode_info->height - 1) / (framebuffer_height - 1); | |
| 1113 ctm.y_offset = static_cast<float>(output.y) / (framebuffer_height - 1); | |
| 1114 return ctm; | |
| 1115 } | |
| 1116 | |
| 1117 float OutputConfigurator::GetMirroredDisplayAreaRatio( | 1025 float OutputConfigurator::GetMirroredDisplayAreaRatio( |
| 1118 const OutputConfigurator::OutputSnapshot& output) { | 1026 const OutputConfigurator::OutputSnapshot& output) { |
| 1119 float area_ratio = 1.0f; | 1027 float area_ratio = 1.0f; |
| 1120 const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); | 1028 const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); |
| 1121 const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); | 1029 const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); |
| 1122 | 1030 |
| 1123 if (!native_mode_info || !mirror_mode_info || | 1031 if (!native_mode_info || !mirror_mode_info || |
| 1124 native_mode_info->height == 0 || mirror_mode_info->height == 0 || | 1032 native_mode_info->height == 0 || mirror_mode_info->height == 0 || |
| 1125 native_mode_info->width == 0 || mirror_mode_info->width == 0) | 1033 native_mode_info->width == 0 || mirror_mode_info->width == 0) |
| 1126 return area_ratio; | 1034 return area_ratio; |
| 1127 | 1035 |
| 1128 float width_ratio = static_cast<float>(mirror_mode_info->width) / | 1036 float width_ratio = static_cast<float>(mirror_mode_info->width) / |
| 1129 static_cast<float>(native_mode_info->width); | 1037 static_cast<float>(native_mode_info->width); |
| 1130 float height_ratio = static_cast<float>(mirror_mode_info->height) / | 1038 float height_ratio = static_cast<float>(mirror_mode_info->height) / |
| 1131 static_cast<float>(native_mode_info->height); | 1039 static_cast<float>(native_mode_info->height); |
| 1132 | 1040 |
| 1133 area_ratio = width_ratio * height_ratio; | 1041 area_ratio = width_ratio * height_ratio; |
| 1134 return area_ratio; | 1042 return area_ratio; |
| 1135 } | 1043 } |
| 1136 | 1044 |
| 1137 } // namespace chromeos | 1045 } // namespace chromeos |
| OLD | NEW |