OLD | NEW |
---|---|
(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 "webrtc/base/checks.h" | |
16 | |
17 namespace webrtc { | |
18 | |
19 bool DxgiDuplicatorContainer::SingleEntry::Enter() { | |
Sergey Ulanov
2016/07/08 22:36:54
I don't think you really need SingleEntry.
Hzj_jie
2016/07/11 00:55:00
Same as below.
| |
20 rtc::CritScope lock(&lock_); | |
21 if (entered_) { | |
22 return false; | |
23 } | |
24 entered_ = true; | |
25 return true; | |
26 } | |
27 | |
28 void DxgiDuplicatorContainer::SingleEntry::Exit() { | |
29 rtc::CritScope lock(&lock_); | |
30 RTC_DCHECK(entered_); | |
31 entered_ = false; | |
32 } | |
33 | |
34 bool DxgiDuplicatorContainer::SingleEntry::Hold() const { | |
35 rtc::CritScope lock(&lock_); | |
36 return entered_; | |
37 } | |
38 | |
39 class DxgiDuplicatorContainer::AutoExit { | |
40 public: | |
41 explicit AutoExit(DxgiDuplicatorContainer::SingleEntry* gate) : gate_(gate) { | |
42 RTC_DCHECK(gate_); | |
43 } | |
44 | |
45 ~AutoExit() { gate_->Exit(); } | |
46 | |
47 private: | |
48 DxgiDuplicatorContainer::SingleEntry* gate_; | |
49 }; | |
50 | |
51 /* static */ DxgiDuplicatorContainer* DxgiDuplicatorContainer::Instance() { | |
Sergey Ulanov
2016/07/08 22:36:54
Move the comment to a separate line:
// static
Dx
Hzj_jie
2016/07/11 00:55:00
Done.
| |
52 // The static instance won't be deleted to ensure it can be used by other | |
53 // threads even during program exiting. | |
54 static DxgiDuplicatorContainer* instance = new DxgiDuplicatorContainer(); | |
55 return instance; | |
56 } | |
57 | |
58 DxgiDuplicatorContainer::~DxgiDuplicatorContainer() { | |
59 rtc::CritScope lock(&lock_); | |
60 Deinitialize(); | |
61 } | |
62 | |
63 bool DxgiDuplicatorContainer::Prepare() { | |
64 // If the instance has been initialized already, does nothing and returns | |
65 // true. | |
66 { | |
67 rtc::CritScope lock(&lock_); | |
68 if (!devices_.empty()) { | |
69 return true; | |
70 } | |
71 } | |
72 | |
73 if (initializing_.Enter()) { | |
Sergey Ulanov
2016/07/08 22:36:54
I think you can implement the same thing without S
Hzj_jie
2016/07/11 00:55:00
Hold on, this logic won't correct.
If the Event is
| |
74 AutoExit exit(&initializing_); | |
75 rtc::CritScope lock(&lock_); | |
76 if (!devices_.empty()) { | |
77 // Another thread has initialized this instance before this thread reaches | |
78 // line initializing_.Enter(), so does nothing and returns true. | |
Sergey Ulanov
2016/07/08 22:36:55
How is that possible?
Hzj_jie
2016/07/11 00:55:00
Another thread has called initializing_.Exit befor
| |
79 return true; | |
80 } | |
81 | |
82 if (DoInitialize()) { | |
83 return true; | |
84 } | |
85 | |
86 Deinitialize(); | |
87 return false; | |
88 } else { | |
89 // Some other thread is initializing, wait for its finish and check the | |
90 // result. | |
91 while (initializing_.Hold()) { | |
92 rtc::CritScope lock(&lock_); | |
93 } | |
94 return !devices_.empty(); | |
Sergey Ulanov
2016/07/08 22:36:54
Here the case when initialization has failed and w
Sergey Ulanov
2016/07/08 22:36:54
don't you need to hold the lock_ when verifying th
Hzj_jie
2016/07/11 00:55:00
If there is no device for any reason, DxgiDuplicat
Hzj_jie
2016/07/11 00:55:00
Yes, I missed.
| |
95 } | |
96 } | |
97 | |
98 void DxgiDuplicatorContainer::Deinitialize() { | |
99 desktop_rect_ = DesktopRect(); | |
100 duplicators_.clear(); | |
101 devices_.clear(); | |
102 } | |
103 | |
104 bool DxgiDuplicatorContainer::DoInitialize() { | |
105 RTC_DCHECK(desktop_rect_.is_empty()); | |
106 RTC_DCHECK(duplicators_.empty()); | |
107 RTC_DCHECK(devices_.empty()); | |
108 | |
109 devices_ = D3dDevice::EnumDevices(); | |
Sergey Ulanov
2016/07/08 22:36:54
We enumerate devices only once here, but they can
Hzj_jie
2016/07/11 00:55:00
Yes, that's the reason we call Prepare each time b
| |
110 if (devices_.empty()) { | |
111 return false; | |
112 } | |
113 | |
114 for (size_t i = 0; i < devices_.size(); i++) { | |
115 duplicators_.emplace_back(); | |
116 if (!duplicators_.back().Initialize(devices_[i])) { | |
117 return false; | |
118 } | |
119 if (desktop_rect_.is_empty()) { | |
120 desktop_rect_ = duplicators_.back().desktop_rect(); | |
121 } else { | |
122 desktop_rect_.JoinWith(duplicators_.back().desktop_rect()); | |
123 } | |
124 } | |
125 | |
126 HDC hdc = GetDC(nullptr); | |
127 // Use old DPI value if failed. | |
128 if (hdc != nullptr) { | |
129 dpi_.set(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY)); | |
Sergey Ulanov
2016/07/08 22:36:55
dpi can change dynamically, but this class won't d
Hzj_jie
2016/07/11 00:55:00
Same as above, we will reset the dpi_ once display
| |
130 ReleaseDC(nullptr, hdc); | |
131 } | |
132 | |
133 return true; | |
134 } | |
135 | |
136 DesktopRect DxgiDuplicatorContainer::ScreenRect(int id) const { | |
137 if (id < 0) { | |
Sergey Ulanov
2016/07/08 22:36:54
DCHECK(id >= 0)
Hzj_jie
2016/07/11 00:55:00
Done.
| |
138 return DesktopRect(); | |
139 } | |
140 rtc::CritScope lock(&lock_); | |
141 for (size_t i = 0; i < duplicators_.size(); i++) { | |
142 if (id >= duplicators_[i].screen_count()) { | |
143 id -= duplicators_[i].screen_count(); | |
144 } else { | |
145 return duplicators_[i].ScreenRect(id); | |
146 } | |
147 } | |
148 return DesktopRect(); | |
149 } | |
150 | |
151 int DxgiDuplicatorContainer::ScreenCount() const { | |
152 rtc::CritScope lock(&lock_); | |
153 int result = 0; | |
154 for (size_t i = 0; i < duplicators_.size(); i++) { | |
155 result += duplicators_[i].screen_count(); | |
156 } | |
157 return result; | |
158 } | |
159 | |
160 bool DxgiDuplicatorContainer::Duplicate(DesktopFrame* target, | |
161 const DesktopFrame* last_frame) { | |
162 RTC_DCHECK(target); | |
163 if (last_frame != nullptr && !target->size().equals(last_frame->size())) { | |
164 return false; | |
165 } | |
166 target->mutable_updated_region()->Clear(); | |
167 rtc::CritScope lock(&lock_); | |
168 for (size_t i = 0; i < duplicators_.size(); i++) { | |
169 if (!duplicators_[i].Duplicate(target, last_frame)) { | |
170 Deinitialize(); | |
171 return false; | |
172 } | |
173 } | |
174 target->set_dpi(dpi()); | |
175 return true; | |
176 } | |
177 | |
178 bool DxgiDuplicatorContainer::Duplicate(int id, | |
179 DesktopFrame* target, | |
180 const DesktopFrame* last_frame) { | |
181 RTC_DCHECK(target); | |
182 if (id < 0) { | |
183 return false; | |
184 } | |
185 if (last_frame != nullptr && !target->size().equals(last_frame->size())) { | |
186 return false; | |
187 } | |
188 target->mutable_updated_region()->Clear(); | |
189 rtc::CritScope lock(&lock_); | |
190 for (size_t i = 0; i < duplicators_.size(); i++) { | |
191 if (id >= duplicators_[i].screen_count()) { | |
192 id -= duplicators_[i].screen_count(); | |
193 } else { | |
194 if (duplicators_[i].Duplicate(id, target, last_frame)) { | |
195 target->set_dpi(dpi()); | |
196 return true; | |
197 } | |
198 Deinitialize(); | |
199 return false; | |
200 } | |
201 } | |
202 // id >= ScreenCount() | |
203 return false; | |
204 } | |
205 | |
206 } // namespace webrtc | |
OLD | NEW |