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 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
91 for (size_t i = 0; i < outputs.size(); ++i) | 91 for (size_t i = 0; i < outputs.size(); ++i) |
92 has_internal_output |= outputs[i].is_internal; | 92 has_internal_output |= outputs[i].is_internal; |
93 | 93 |
94 // "Projecting" is defined as having more than 1 output connected while at | 94 // "Projecting" is defined as having more than 1 output connected while at |
95 // least one of them is an internal output. | 95 // least one of them is an internal output. |
96 return has_internal_output && (connected_output_count > 1); | 96 return has_internal_output && (connected_output_count > 1); |
97 } | 97 } |
98 | 98 |
99 } // namespace | 99 } // namespace |
100 | 100 |
101 OutputConfigurator::CoordinateTransformation::CoordinateTransformation() | |
102 : x_scale(1.0), | |
103 x_offset(0.0), | |
104 y_scale(1.0), | |
105 y_offset(0.0) {} | |
106 | |
101 OutputConfigurator::OutputSnapshot::OutputSnapshot() | 107 OutputConfigurator::OutputSnapshot::OutputSnapshot() |
102 : output(None), | 108 : output(None), |
103 crtc(None), | 109 crtc(None), |
104 current_mode(None), | 110 current_mode(None), |
105 native_mode(None), | 111 native_mode(None), |
106 mirror_mode(None), | 112 mirror_mode(None), |
107 selected_mode(None), | 113 selected_mode(None), |
114 x(0), | |
108 y(0), | 115 y(0), |
109 height(0), | |
110 is_internal(false), | 116 is_internal(false), |
111 is_aspect_preserving_scaling(false), | 117 is_aspect_preserving_scaling(false), |
112 touch_device_id(0), | 118 touch_device_id(0), |
113 display_id(0), | 119 display_id(0), |
114 has_display_id(false) {} | 120 has_display_id(false) {} |
115 | 121 |
116 OutputConfigurator::CoordinateTransformation::CoordinateTransformation() | |
117 : x_scale(1.0), | |
118 x_offset(0.0), | |
119 y_scale(1.0), | |
120 y_offset(0.0) {} | |
121 | |
122 OutputConfigurator::CrtcConfig::CrtcConfig() | |
123 : crtc(None), | |
124 x(0), | |
125 y(0), | |
126 mode(None), | |
127 output(None) {} | |
128 | |
129 OutputConfigurator::CrtcConfig::CrtcConfig(RRCrtc crtc, | |
130 int x, int y, | |
131 RRMode mode, | |
132 RROutput output) | |
133 : crtc(crtc), | |
134 x(x), | |
135 y(y), | |
136 mode(mode), | |
137 output(output) {} | |
138 | |
139 bool OutputConfigurator::TestApi::SendOutputChangeEvents(bool connected) { | 122 bool OutputConfigurator::TestApi::SendOutputChangeEvents(bool connected) { |
140 XRRScreenChangeNotifyEvent screen_event; | 123 XRRScreenChangeNotifyEvent screen_event; |
141 memset(&screen_event, 0, sizeof(screen_event)); | 124 memset(&screen_event, 0, sizeof(screen_event)); |
142 screen_event.type = xrandr_event_base_ + RRScreenChangeNotify; | 125 screen_event.type = xrandr_event_base_ + RRScreenChangeNotify; |
143 configurator_->Dispatch( | 126 configurator_->Dispatch( |
144 reinterpret_cast<const base::NativeEvent>(&screen_event)); | 127 reinterpret_cast<const base::NativeEvent>(&screen_event)); |
145 | 128 |
146 XRROutputChangeNotifyEvent notify_event; | 129 XRROutputChangeNotifyEvent notify_event; |
147 memset(¬ify_event, 0, sizeof(notify_event)); | 130 memset(¬ify_event, 0, sizeof(notify_event)); |
148 notify_event.type = xrandr_event_base_ + RRNotify; | 131 notify_event.type = xrandr_event_base_ + RRNotify; |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
411 } | 394 } |
412 | 395 |
413 bool OutputConfigurator::EnterState( | 396 bool OutputConfigurator::EnterState( |
414 OutputState output_state, | 397 OutputState output_state, |
415 DisplayPowerState power_state, | 398 DisplayPowerState power_state, |
416 const std::vector<OutputSnapshot>& outputs) { | 399 const std::vector<OutputSnapshot>& outputs) { |
417 std::vector<bool> output_power; | 400 std::vector<bool> output_power; |
418 int num_on_outputs = GetOutputPower(outputs, power_state, &output_power); | 401 int num_on_outputs = GetOutputPower(outputs, power_state, &output_power); |
419 VLOG(1) << "EnterState: output=" << OutputStateToString(output_state) | 402 VLOG(1) << "EnterState: output=" << OutputStateToString(output_state) |
420 << " power=" << DisplayPowerStateToString(power_state); | 403 << " power=" << DisplayPowerStateToString(power_state); |
404 | |
405 // Framebuffer dimensions. | |
406 int width = 0, height = 0; | |
407 std::vector<OutputSnapshot> updated_outputs = outputs; | |
408 | |
421 switch (output_state) { | 409 switch (output_state) { |
422 case STATE_HEADLESS: | 410 case STATE_HEADLESS: |
oshima
2013/08/08 01:19:49
do you think we can nuke STATE_HEADLESS?
Daniel Erat
2013/08/08 16:07:37
What's the alternate proposal? Do you think we sho
oshima
2013/08/08 16:52:09
Exit early if there is no output and just leave th
| |
423 if (outputs.size() != 0) { | 411 if (outputs.size() != 0) { |
424 LOG(WARNING) << "Ignoring request to enter headless mode with " | 412 LOG(WARNING) << "Ignoring request to enter headless mode with " |
425 << outputs.size() << " connected output(s)"; | 413 << outputs.size() << " connected output(s)"; |
426 return false; | 414 return false; |
427 } | 415 } |
428 break; | 416 break; |
429 case STATE_SINGLE: { | 417 case STATE_SINGLE: { |
430 // If there are multiple outputs connected, only one should be turned on. | 418 // If there are multiple outputs connected, only one should be turned on. |
431 if (outputs.size() != 1 && num_on_outputs != 1) { | 419 if (outputs.size() != 1 && num_on_outputs != 1) { |
432 LOG(WARNING) << "Ignoring request to enter single mode with " | 420 LOG(WARNING) << "Ignoring request to enter single mode with " |
433 << outputs.size() << " connected outputs and " | 421 << outputs.size() << " connected outputs and " |
434 << num_on_outputs << " turned on"; | 422 << num_on_outputs << " turned on"; |
435 return false; | 423 return false; |
436 } | 424 } |
437 | 425 |
438 // Determine which output to use. | 426 for (size_t i = 0; i < updated_outputs.size(); ++i) { |
439 const OutputSnapshot& output = outputs.size() == 1 ? outputs[0] : | 427 OutputSnapshot* output = &updated_outputs[i]; |
440 (output_power[0] ? outputs[0] : outputs[1]); | 428 output->x = 0; |
441 int width = 0, height = 0; | 429 output->y = 0; |
442 if (!delegate_->GetModeDetails( | 430 output->current_mode = output_power[i] ? output->selected_mode : None; |
443 output.selected_mode, &width, &height, NULL)) | |
444 return false; | |
445 | 431 |
446 std::vector<CrtcConfig> configs(outputs.size()); | 432 if (output_power[i] || outputs.size() == 1) { |
447 for (size_t i = 0; i < outputs.size(); ++i) { | 433 if (!delegate_->GetModeDetails( |
448 configs[i] = CrtcConfig( | 434 output->selected_mode, &width, &height, NULL)) |
449 outputs[i].crtc, 0, 0, | 435 return false; |
450 output_power[i] ? outputs[i].selected_mode : None, | |
451 outputs[i].output); | |
452 } | |
453 delegate_->CreateFrameBuffer(width, height, configs); | |
454 | |
455 for (size_t i = 0; i < outputs.size(); ++i) { | |
456 delegate_->ConfigureCrtc(&configs[i]); | |
457 if (outputs[i].touch_device_id) { | |
458 delegate_->ConfigureCTM(outputs[i].touch_device_id, | |
459 CoordinateTransformation()); | |
460 } | 436 } |
461 } | 437 } |
462 break; | 438 break; |
463 } | 439 } |
464 case STATE_DUAL_MIRROR: { | 440 case STATE_DUAL_MIRROR: { |
465 if (outputs.size() != 2 || (num_on_outputs != 0 && num_on_outputs != 2)) { | 441 if (outputs.size() != 2 || (num_on_outputs != 0 && num_on_outputs != 2)) { |
466 LOG(WARNING) << "Ignoring request to enter mirrored mode with " | 442 LOG(WARNING) << "Ignoring request to enter mirrored mode with " |
467 << outputs.size() << " connected output(s) and " | 443 << outputs.size() << " connected output(s) and " |
468 << num_on_outputs << " turned on"; | 444 << num_on_outputs << " turned on"; |
469 return false; | 445 return false; |
470 } | 446 } |
471 | 447 |
472 int width = 0, height = 0; | |
473 if (!delegate_->GetModeDetails( | 448 if (!delegate_->GetModeDetails( |
474 outputs[0].mirror_mode, &width, &height, NULL)) { | 449 outputs[0].mirror_mode, &width, &height, NULL)) |
475 return false; | 450 return false; |
476 } | |
477 | |
478 std::vector<CrtcConfig> configs(outputs.size()); | |
479 for (size_t i = 0; i < outputs.size(); ++i) { | |
480 configs[i] = CrtcConfig( | |
481 outputs[i].crtc, 0, 0, | |
482 output_power[i] ? outputs[i].mirror_mode : None, | |
483 outputs[i].output); | |
484 } | |
485 delegate_->CreateFrameBuffer(width, height, configs); | |
486 | 451 |
487 for (size_t i = 0; i < outputs.size(); ++i) { | 452 for (size_t i = 0; i < outputs.size(); ++i) { |
488 delegate_->ConfigureCrtc(&configs[i]); | 453 OutputSnapshot* output = &updated_outputs[i]; |
489 if (outputs[i].touch_device_id) { | 454 output->x = 0; |
490 CoordinateTransformation ctm; | 455 output->y = 0; |
456 output->current_mode = output_power[i] ? output->mirror_mode : None; | |
457 if (output->touch_device_id) { | |
491 // CTM needs to be calculated if aspect preserving scaling is used. | 458 // CTM needs to be calculated if aspect preserving scaling is used. |
492 // Otherwise, assume it is full screen, and use identity CTM. | 459 // Otherwise, assume it is full screen, and use identity CTM. |
493 if (outputs[i].mirror_mode != outputs[i].native_mode && | 460 if (output->mirror_mode != output->native_mode && |
494 outputs[i].is_aspect_preserving_scaling) { | 461 output->is_aspect_preserving_scaling) { |
495 ctm = GetMirrorModeCTM(&outputs[i]); | 462 output->transform = GetMirrorModeCTM(output); |
496 mirrored_display_area_ratio_map_[outputs[i].touch_device_id] = | 463 mirrored_display_area_ratio_map_[output->touch_device_id] = |
497 GetMirroredDisplayAreaRatio(&outputs[i]); | 464 GetMirroredDisplayAreaRatio(output); |
498 } | 465 } |
499 delegate_->ConfigureCTM(outputs[i].touch_device_id, ctm); | |
500 } | 466 } |
501 } | 467 } |
502 break; | 468 break; |
503 } | 469 } |
504 case STATE_DUAL_EXTENDED: { | 470 case STATE_DUAL_EXTENDED: { |
505 if (outputs.size() != 2 || (num_on_outputs != 0 && num_on_outputs != 2)) { | 471 if (outputs.size() != 2 || (num_on_outputs != 0 && num_on_outputs != 2)) { |
506 LOG(WARNING) << "Ignoring request to enter extended mode with " | 472 LOG(WARNING) << "Ignoring request to enter extended mode with " |
507 << outputs.size() << " connected output(s) and " | 473 << outputs.size() << " connected output(s) and " |
508 << num_on_outputs << " turned on"; | 474 << num_on_outputs << " turned on"; |
509 return false; | 475 return false; |
510 } | 476 } |
511 | 477 |
512 // Pairs are [width, height] corresponding to the given output's mode. | 478 // Pairs are [width, height] corresponding to the given output's mode. |
513 std::vector<std::pair<int, int> > mode_sizes(outputs.size()); | 479 std::vector<std::pair<int, int> > mode_sizes(outputs.size()); |
514 std::vector<CrtcConfig> configs(outputs.size()); | |
515 int width = 0, height = 0; | |
516 | 480 |
517 for (size_t i = 0; i < outputs.size(); ++i) { | 481 for (size_t i = 0; i < outputs.size(); ++i) { |
518 if (!delegate_->GetModeDetails(outputs[i].selected_mode, | 482 if (!delegate_->GetModeDetails(outputs[i].selected_mode, |
519 &(mode_sizes[i].first), &(mode_sizes[i].second), NULL)) { | 483 &(mode_sizes[i].first), &(mode_sizes[i].second), NULL)) { |
520 return false; | 484 return false; |
521 } | 485 } |
522 | 486 |
523 configs[i] = CrtcConfig( | 487 OutputSnapshot* output = &updated_outputs[i]; |
524 outputs[i].crtc, 0, (height ? height + kVerticalGap : 0), | 488 output->x = 0; |
525 output_power[i] ? outputs[i].selected_mode : None, | 489 output->y = height ? height + kVerticalGap : 0; |
526 outputs[i].output); | 490 output->current_mode = output_power[i] ? output->selected_mode : None; |
527 | 491 |
528 // Retain the full screen size even if all outputs are off so the | 492 // Retain the full screen size even if all outputs are off so the |
529 // same desktop configuration can be restored when the outputs are | 493 // same desktop configuration can be restored when the outputs are |
530 // turned back on. | 494 // turned back on. |
531 width = std::max<int>(width, mode_sizes[i].first); | 495 width = std::max<int>(width, mode_sizes[i].first); |
532 height += (height ? kVerticalGap : 0) + mode_sizes[i].second; | 496 height += (height ? kVerticalGap : 0) + mode_sizes[i].second; |
533 } | 497 } |
534 | 498 |
535 delegate_->CreateFrameBuffer(width, height, configs); | |
536 | |
537 for (size_t i = 0; i < outputs.size(); ++i) { | 499 for (size_t i = 0; i < outputs.size(); ++i) { |
538 delegate_->ConfigureCrtc(&configs[i]); | 500 OutputSnapshot* output = &updated_outputs[i]; |
539 if (outputs[i].touch_device_id) { | 501 if (output->touch_device_id) { |
540 CoordinateTransformation ctm; | 502 CoordinateTransformation* ctm = &(output->transform); |
541 ctm.x_scale = static_cast<float>(mode_sizes[i].first) / width; | 503 ctm->x_scale = static_cast<float>(mode_sizes[i].first) / width; |
542 ctm.x_offset = static_cast<float>(configs[i].x) / width; | 504 ctm->x_offset = static_cast<float>(output->x) / width; |
543 ctm.y_scale = static_cast<float>(mode_sizes[i].second) / height; | 505 ctm->y_scale = static_cast<float>(mode_sizes[i].second) / height; |
544 ctm.y_offset = static_cast<float>(configs[i].y) / height; | 506 ctm->y_offset = static_cast<float>(output->y) / height; |
545 delegate_->ConfigureCTM(outputs[i].touch_device_id, ctm); | |
546 } | 507 } |
547 } | 508 } |
548 break; | 509 break; |
549 } | 510 } |
550 default: | 511 default: |
551 NOTREACHED() << "Got request to enter output state " << output_state | 512 NOTREACHED() << "Got request to enter output state " << output_state |
552 << " with " << outputs.size() << " output(s)"; | 513 << " with " << outputs.size() << " output(s)"; |
553 return false; | 514 return false; |
oshima
2013/08/08 01:19:49
let's remove default because output_state is enum.
Daniel Erat
2013/08/08 16:07:37
It was covering STATE_INVALID. I've added a separa
| |
554 } | 515 } |
555 | 516 |
517 // Finally, apply the desired changes. | |
518 DCHECK_EQ(outputs.size(), updated_outputs.size()); | |
519 if (!outputs.empty()) { | |
520 delegate_->CreateFrameBuffer(width, height, updated_outputs); | |
521 for (size_t i = 0; i < outputs.size(); ++i) { | |
522 const OutputSnapshot& output = updated_outputs[i]; | |
523 if (delegate_->ConfigureCrtc(output.crtc, output.current_mode, | |
524 output.output, output.x, output.y)) { | |
525 if (output.touch_device_id) | |
526 delegate_->ConfigureCTM(output.touch_device_id, output.transform); | |
527 } else { | |
528 LOG(WARNING) << "Unable to configure CRTC " << output.crtc << ":" | |
529 << " mode=" << output.current_mode | |
530 << " output=" << output.output | |
531 << " x=" << output.x | |
532 << " y=" << output.y; | |
533 updated_outputs[i] = outputs[i]; | |
534 } | |
535 } | |
536 } | |
537 | |
556 output_state_ = output_state; | 538 output_state_ = output_state; |
557 power_state_ = power_state; | 539 power_state_ = power_state; |
540 cached_outputs_ = updated_outputs; | |
558 return true; | 541 return true; |
559 } | 542 } |
560 | 543 |
561 OutputState OutputConfigurator::GetOutputState( | 544 OutputState OutputConfigurator::GetOutputState( |
562 const std::vector<OutputSnapshot>& outputs, | 545 const std::vector<OutputSnapshot>& outputs, |
563 DisplayPowerState power_state) const { | 546 DisplayPowerState power_state) const { |
564 int num_on_outputs = GetOutputPower(outputs, power_state, NULL); | 547 int num_on_outputs = GetOutputPower(outputs, power_state, NULL); |
565 switch (outputs.size()) { | 548 switch (outputs.size()) { |
566 case 0: | 549 case 0: |
567 return STATE_HEADLESS; | 550 return STATE_HEADLESS; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
648 float width_ratio = static_cast<float>(mirror_mode_width) / | 631 float width_ratio = static_cast<float>(mirror_mode_width) / |
649 static_cast<float>(native_mode_width); | 632 static_cast<float>(native_mode_width); |
650 float height_ratio = static_cast<float>(mirror_mode_height) / | 633 float height_ratio = static_cast<float>(mirror_mode_height) / |
651 static_cast<float>(native_mode_height); | 634 static_cast<float>(native_mode_height); |
652 | 635 |
653 area_ratio = width_ratio * height_ratio; | 636 area_ratio = width_ratio * height_ratio; |
654 return area_ratio; | 637 return area_ratio; |
655 } | 638 } |
656 | 639 |
657 } // namespace chromeos | 640 } // namespace chromeos |
OLD | NEW |