1 /*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/modules/desktop_capture/win/dxgi_adapter_duplicator.h"
12
13 #include <comdef.h>
14 #include <DXGI.h>
15
16 #include <algorithm>
17
18 #include "webrtc/base/checks.h"
19 #include "webrtc/base/logging.h"
20
21 namespace webrtc {
22
23 using Microsoft::WRL::ComPtr;
24
25 namespace {
26
IsValidRect(const RECT & rect)27 bool IsValidRect(const RECT& rect) {
28 return rect.left >= 0 && rect.top >= 0 && rect.right > rect.left &&
29 rect.bottom > rect.top;
30 }
31
32 } // namespace
33
34 DxgiAdapterDuplicator::Context::Context() = default;
35 DxgiAdapterDuplicator::Context::Context(const Context& other) = default;
36 DxgiAdapterDuplicator::Context::~Context() = default;
37
DxgiAdapterDuplicator(const D3dDevice & device)38 DxgiAdapterDuplicator::DxgiAdapterDuplicator(const D3dDevice& device)
39 : device_(device) {}
40 DxgiAdapterDuplicator::DxgiAdapterDuplicator(DxgiAdapterDuplicator&&) = default;
41 DxgiAdapterDuplicator::~DxgiAdapterDuplicator() = default;
42
Initialize()43 bool DxgiAdapterDuplicator::Initialize() {
44 if (DoInitialize()) {
45 return true;
46 }
47 duplicators_.clear();
48 return false;
49 }
50
DoInitialize()51 bool DxgiAdapterDuplicator::DoInitialize() {
52 for (int i = 0;; i++) {
53 ComPtr<IDXGIOutput> output;
54 _com_error error =
55 device_.dxgi_adapter()->EnumOutputs(i, output.GetAddressOf());
56 if (error.Error() == DXGI_ERROR_NOT_FOUND) {
57 break;
58 }
59
60 if (error.Error() != S_OK || !output) {
61 LOG(LS_WARNING) << "IDXGIAdapter::EnumOutputs returns an unexpected "
62 "result "
63 << error.ErrorMessage() << " with error code"
64 << error.Error();
65 return false;
66 }
67
68 DXGI_OUTPUT_DESC desc;
69 error = output->GetDesc(&desc);
70 if (error.Error() == S_OK) {
71 if (desc.AttachedToDesktop && IsValidRect(desc.DesktopCoordinates)) {
72 ComPtr<IDXGIOutput1> output1;
73 error = output.As(&output1);
74 if (error.Error() != S_OK || !output1) {
75 LOG(LS_WARNING) << "Failed to convert IDXGIOutput to IDXGIOutput1, "
76 "this usually means the system does not support "
77 "DirectX 11";
78 return false;
79 }
80 duplicators_.emplace_back(device_, output1, desc);
81 if (!duplicators_.back().Initialize()) {
82 return false;
83 }
84 if (desktop_rect_.is_empty()) {
85 desktop_rect_ = duplicators_.back().desktop_rect();
86 } else {
87 const DesktopRect& left = desktop_rect_;
88 const DesktopRect& right = duplicators_.back().desktop_rect();
89 desktop_rect_ =
90 DesktopRect::MakeLTRB(std::min(left.left(), right.left()),
91 std::min(left.top(), right.top()),
92 std::max(left.right(), right.right()),
93 std::max(left.bottom(), right.bottom()));
94 }
95 }
96 } else {
97 LOG(LS_WARNING) << "Failed to get output description of device " << i
98 << ", ignore.";
99 }
100 }
101 return true;
102 }
103
Setup(Context * context)104 void DxgiAdapterDuplicator::Setup(Context* context) {
105 RTC_DCHECK(context->contexts.empty());
106 context->contexts.resize(duplicators_.size());
107 for (size_t i = 0; i < duplicators_.size(); i++) {
108 duplicators_[i].Setup(&context->contexts[i]);
109 }
110 }
111
Unregister(const Context * const context)112 void DxgiAdapterDuplicator::Unregister(const Context* const context) {
113 RTC_DCHECK_EQ(context->contexts.size(), duplicators_.size());
114 for (size_t i = 0; i < duplicators_.size(); i++) {
115 duplicators_[i].Unregister(&context->contexts[i]);
116 }
117 }
118
Duplicate(Context * context,SharedDesktopFrame * target)119 bool DxgiAdapterDuplicator::Duplicate(Context* context,
120 SharedDesktopFrame* target) {
121 RTC_DCHECK_EQ(context->contexts.size(), duplicators_.size());
122 for (size_t i = 0; i < duplicators_.size(); i++) {
123 if (!duplicators_[i].Duplicate(&context->contexts[i],
124 duplicators_[i].desktop_rect().top_left(),
125 target)) {
126 return false;
127 }
128 }
129 return true;
130 }
131
DuplicateMonitor(Context * context,int monitor_id,SharedDesktopFrame * target)132 bool DxgiAdapterDuplicator::DuplicateMonitor(Context* context,
133 int monitor_id,
134 SharedDesktopFrame* target) {
135 RTC_DCHECK(monitor_id >= 0 &&
136 monitor_id < static_cast<int>(duplicators_.size()) &&
137 context->contexts.size() == duplicators_.size());
138 return duplicators_[monitor_id].Duplicate(&context->contexts[monitor_id],
139 DesktopVector(), target);
140 }
141
ScreenRect(int id) const142 DesktopRect DxgiAdapterDuplicator::ScreenRect(int id) const {
143 RTC_DCHECK(id >= 0 && id < static_cast<int>(duplicators_.size()));
144 return duplicators_[id].desktop_rect();
145 }
146
147 } // namespace webrtc
148