Chromium Code Reviews| 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 |