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

Side by Side Diff: webrtc/modules/desktop_capture/win/dxgi_duplicator_container.cc

Issue 2099123002: [Chromoting] Improve DirectX capturer to support multiple outputs (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Resolve review comments Created 4 years, 5 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
OLDNEW
(Empty)
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_duplicator_container.h"
12
13 #include <windows.h>
14
15 #include <algorithm>
16
17 #include "webrtc/base/checks.h"
18 #include "webrtc/base/timeutils.h"
19
20 namespace webrtc {
21
22 bool DxgiDuplicatorContainer::SingleEntry::Enter() {
23 rtc::CritScope lock(&lock_);
24 if (entered_) {
25 return false;
26 }
27 entered_ = true;
28 return true;
29 }
30
31 void DxgiDuplicatorContainer::SingleEntry::Exit() {
32 rtc::CritScope lock(&lock_);
33 RTC_DCHECK(entered_);
34 entered_ = false;
35 }
36
37 bool DxgiDuplicatorContainer::SingleEntry::Hold() const {
38 rtc::CritScope lock(&lock_);
39 return entered_;
40 }
41
42 class DxgiDuplicatorContainer::AutoExit {
43 public:
44 explicit AutoExit(DxgiDuplicatorContainer::SingleEntry* gate) : gate_(gate) {
45 RTC_DCHECK(gate_);
46 }
47
48 ~AutoExit() { gate_->Exit(); }
49
50 private:
51 DxgiDuplicatorContainer::SingleEntry* gate_;
52 };
53
54 // static
55 DxgiDuplicatorContainer* DxgiDuplicatorContainer::Instance() {
56 // The static instance won't be deleted to ensure it can be used by other
57 // threads even during program exiting.
58 static DxgiDuplicatorContainer* instance = new DxgiDuplicatorContainer();
59 return instance;
60 }
61
62 DxgiDuplicatorContainer::~DxgiDuplicatorContainer() {
63 rtc::CritScope lock(&lock_);
64 Deinitialize();
65 }
66
67 bool DxgiDuplicatorContainer::Prepare(DxgiContext* context) {
68 if (Prepare()) {
69 Setup(context);
70 return true;
71 }
72 return false;
73 }
74
75 bool DxgiDuplicatorContainer::Prepare() {
76 // If the instance has been initialized already, does nothing and returns
77 // true.
78 {
79 rtc::CritScope lock(&lock_);
80 if (!devices_.empty()) {
81 return true;
82 }
83 }
84
85 if (initializing_.Enter()) {
86 AutoExit exit(&initializing_);
87 rtc::CritScope lock(&lock_);
88 if (!devices_.empty()) {
89 // Another thread has initialized this instance before this thread reaches
90 // line initializing_.Enter(), so does nothing and returns true.
91 return true;
92 }
93
94 if (DoInitialize()) {
95 return true;
96 }
97
98 Deinitialize();
99 return false;
100 } else {
101 // Some other thread is initializing, wait for its finish and check the
102 // result.
103 while (initializing_.Hold()) {
104 rtc::CritScope lock(&lock_);
105 }
106 rtc::CritScope lock(&lock_);
107 return !devices_.empty();
108 }
109 }
110
111 void DxgiDuplicatorContainer::Setup(DxgiContext* context) {
112 rtc::CritScope lock(&lock_);
113 if (context->initialize_time_nanos_ <= initialize_time_nanos_) {
114 context->contexts_.clear();
115 context->contexts_.resize(devices_.size());
116 for (size_t i = 0; i < devices_.size(); i++) {
117 duplicators_[i].Setup(&context->contexts_[i]);
118 }
119 // Times may not change, so following assignment can make sure we won't
120 // setup this context instance again.
121 context->initialize_time_nanos_ = initialize_time_nanos_ + 1;
122 }
123 }
124
125 void DxgiDuplicatorContainer::Deinitialize() {
126 desktop_rect_ = DesktopRect();
127 duplicators_.clear();
128 devices_.clear();
129 }
130
131 bool DxgiDuplicatorContainer::DoInitialize() {
132 RTC_DCHECK(desktop_rect_.is_empty());
133 RTC_DCHECK(duplicators_.empty());
134 RTC_DCHECK(devices_.empty());
135
136 devices_ = D3dDevice::EnumDevices();
137 if (devices_.empty()) {
138 return false;
139 }
140
141 for (size_t i = 0; i < devices_.size(); i++) {
142 duplicators_.emplace_back();
143 if (!duplicators_.back().Initialize(devices_[i])) {
144 return false;
145 }
146 if (desktop_rect_.is_empty()) {
147 desktop_rect_ = duplicators_.back().desktop_rect();
148 } else {
149 const DesktopRect& left = desktop_rect_;
150 const DesktopRect& right = duplicators_.back().desktop_rect();
151 desktop_rect_ = DesktopRect::MakeLTRB(
152 std::min(left.left(), right.left()),
153 std::min(left.top(), right.top()),
154 std::max(left.right(), right.right()),
155 std::max(left.bottom(), right.bottom()));
156 }
157 }
158
159 HDC hdc = GetDC(nullptr);
160 // Use old DPI value if failed.
161 if (hdc != nullptr) {
162 dpi_.set(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
163 ReleaseDC(nullptr, hdc);
164 }
165
166 initialize_time_nanos_ = rtc::TimeNanos();
167 return true;
168 }
169
170 DesktopRect DxgiDuplicatorContainer::ScreenRect(int id) const {
171 RTC_DCHECK(id >= 0);
172 rtc::CritScope lock(&lock_);
173 for (size_t i = 0; i < duplicators_.size(); i++) {
174 if (id >= duplicators_[i].screen_count()) {
175 id -= duplicators_[i].screen_count();
176 } else {
177 return duplicators_[i].ScreenRect(id);
178 }
179 }
180 return DesktopRect();
181 }
182
183 int DxgiDuplicatorContainer::ScreenCount() const {
184 rtc::CritScope lock(&lock_);
185 int result = 0;
186 for (auto& duplicator : duplicators_) {
187 result += duplicator.screen_count();
188 }
189 return result;
190 }
191
192 bool DxgiDuplicatorContainer::Duplicate(DxgiContext* context,
193 DesktopFrame* target,
194 const DesktopFrame* last_frame) {
195 RTC_DCHECK(target);
196 if (last_frame != nullptr && !target->size().equals(last_frame->size())) {
197 return false;
198 }
199 target->mutable_updated_region()->Clear();
200 rtc::CritScope lock(&lock_);
201 if (duplicators_.empty() ||
202 context->contexts_.size() != duplicators_.size()) {
203 // Next Prepare call will initialize duplicators_ or context.
204 return false;
205 }
206 for (size_t i = 0; i < duplicators_.size(); i++) {
207 if (!duplicators_[i].Duplicate(
208 &context->contexts_[i], target, last_frame)) {
209 Deinitialize();
210 return false;
211 }
212 }
213 target->set_dpi(dpi());
214 return true;
215 }
216
217 bool DxgiDuplicatorContainer::Duplicate(DxgiContext* context,
218 int id,
219 DesktopFrame* target,
220 const DesktopFrame* last_frame) {
221 RTC_DCHECK(target);
222 RTC_DCHECK(id >= 0);
223 if (last_frame != nullptr && !target->size().equals(last_frame->size())) {
224 return false;
225 }
226 target->mutable_updated_region()->Clear();
227 rtc::CritScope lock(&lock_);
228 for (size_t i = 0;
229 i < duplicators_.size() && i < context->contexts_.size();
230 i++) {
231 if (id >= duplicators_[i].screen_count()) {
232 id -= duplicators_[i].screen_count();
233 } else {
234 if (duplicators_[i].Duplicate(
235 &context->contexts_[i], id, target, last_frame)) {
236 target->set_dpi(dpi());
237 return true;
238 }
239 Deinitialize();
240 return false;
241 }
242 }
243 // id >= ScreenCount() || context->contexts_.size() != devices_.size()
244 return false;
245 }
246
247 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698