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

Unified 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: Use a self-incremented integer to identify a DxgiDuplicatorContaienr::Initialize 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 side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/desktop_capture/win/dxgi_duplicator_container.cc
diff --git a/webrtc/modules/desktop_capture/win/dxgi_duplicator_container.cc b/webrtc/modules/desktop_capture/win/dxgi_duplicator_container.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5c03c329bb2df3e8636afa178047ac68a4e9d97a
--- /dev/null
+++ b/webrtc/modules/desktop_capture/win/dxgi_duplicator_container.cc
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/desktop_capture/win/dxgi_duplicator_container.h"
+
+#include <windows.h>
+
+#include <algorithm>
+
+#include "webrtc/base/checks.h"
+
+namespace webrtc {
+
+bool DxgiDuplicatorContainer::SingleEntry::Enter() {
+ rtc::CritScope lock(&lock_);
+ if (entered_) {
+ return false;
+ }
+ entered_ = true;
+ return true;
+}
+
+void DxgiDuplicatorContainer::SingleEntry::Exit() {
+ rtc::CritScope lock(&lock_);
+ RTC_DCHECK(entered_);
+ entered_ = false;
+}
+
+bool DxgiDuplicatorContainer::SingleEntry::Hold() const {
+ rtc::CritScope lock(&lock_);
+ return entered_;
+}
+
+class DxgiDuplicatorContainer::AutoExit {
+ public:
+ explicit AutoExit(DxgiDuplicatorContainer::SingleEntry* gate) : gate_(gate) {
+ RTC_DCHECK(gate_);
+ }
+
+ ~AutoExit() { gate_->Exit(); }
+
+ private:
+ DxgiDuplicatorContainer::SingleEntry* gate_;
+};
+
+// static
+DxgiDuplicatorContainer* DxgiDuplicatorContainer::Instance() {
+ // The static instance won't be deleted to ensure it can be used by other
+ // threads even during program exiting.
+ static DxgiDuplicatorContainer* instance = new DxgiDuplicatorContainer();
+ return instance;
+}
+
+DxgiDuplicatorContainer::DxgiDuplicatorContainer() = default;
+
+DxgiDuplicatorContainer::~DxgiDuplicatorContainer() {
+ rtc::CritScope lock(&lock_);
+ Deinitialize();
+}
+
+bool DxgiDuplicatorContainer::Prepare(DxgiContext* context) {
+ if (Prepare()) {
+ Setup(context);
+ return true;
+ }
+ return false;
+}
+
+bool DxgiDuplicatorContainer::Prepare() {
+ // If the instance has been initialized already, does nothing and returns
+ // true.
+ {
+ rtc::CritScope lock(&lock_);
+ if (!duplicators_.empty()) {
+ return true;
+ }
+ }
+
+ if (initializing_.Enter()) {
Sergey Ulanov 2016/07/28 22:15:32 Looking at this again I'm still not sure you reall
Hzj_jie 2016/07/29 02:12:23 Yes, I was wrong, this logic is out-of-date. As we
+ AutoExit exit(&initializing_);
+ rtc::CritScope lock(&lock_);
+ if (!duplicators_.empty()) {
+ // Another thread has initialized this instance before this thread reaches
+ // line initializing_.Enter(), so does nothing and returns true.
+ return true;
+ }
+
+ if (DoInitialize()) {
+ return true;
+ }
+
+ Deinitialize();
+ return false;
+ } else {
+ // Some other thread is initializing, wait for its finish and check the
+ // result.
+ while (initializing_.Hold()) {
+ rtc::CritScope lock(&lock_);
+ }
+ rtc::CritScope lock(&lock_);
+ return !duplicators_.empty();
+ }
+}
+
+bool DxgiDuplicatorContainer::DxgiContextExpired(
+ const DxgiContext* const context) const {
+ return context->identity_ != identity_ ||
+ context->contexts_.size() != duplicators_.size();
+}
+
+void DxgiDuplicatorContainer::Setup(DxgiContext* context) {
+ rtc::CritScope lock(&lock_);
+ if (duplicators_.empty()) {
+ // The most recent initialization has failed. So we do not waste time to
+ // setup DxgiContext, it will be setup again later.
+ return;
+ }
+ if (DxgiContextExpired(context)) {
+ context->contexts_.clear();
+ context->contexts_.resize(duplicators_.size());
+ for (size_t i = 0; i < duplicators_.size(); i++) {
+ duplicators_[i].Setup(&context->contexts_[i]);
+ }
+ context->identity_ = identity_;
+ }
+}
+
+void DxgiDuplicatorContainer::Unregister(const DxgiContext* const context) {
+ rtc::CritScope lock(&lock_);
+ if (DxgiContextExpired(context)) {
+ // The DxgiContext has not been setup after a recent initialization, so it
+ // should not been registered in duplicators.
+ return;
+ }
+ for (size_t i = 0; i < duplicators_.size(); i++) {
+ duplicators_[i].Unregister(&context->contexts_[i]);
+ }
+}
+
+void DxgiDuplicatorContainer::Deinitialize() {
+ desktop_rect_ = DesktopRect();
+ duplicators_.clear();
+}
+
+bool DxgiDuplicatorContainer::DoInitialize() {
+ RTC_DCHECK(desktop_rect_.is_empty());
+ RTC_DCHECK(duplicators_.empty());
+
+ std::vector<D3dDevice> devices = D3dDevice::EnumDevices();
+ if (devices.empty()) {
+ return false;
+ }
+
+ for (size_t i = 0; i < devices.size(); i++) {
+ duplicators_.emplace_back(devices[i]);
Sergey Ulanov 2016/07/28 22:15:32 Please don't use push_back() instead of emplace_ba
Hzj_jie 2016/07/29 02:12:23 Oh, this emplace_back is expected, as devices[i] i
+ if (!duplicators_.back().Initialize()) {
+ return false;
+ }
+ if (desktop_rect_.is_empty()) {
+ desktop_rect_ = duplicators_.back().desktop_rect();
+ } else {
+ const DesktopRect& left = desktop_rect_;
+ const DesktopRect& right = duplicators_.back().desktop_rect();
+ desktop_rect_ =
+ DesktopRect::MakeLTRB(std::min(left.left(), right.left()),
+ std::min(left.top(), right.top()),
+ std::max(left.right(), right.right()),
+ std::max(left.bottom(), right.bottom()));
+ }
+ }
+
+ HDC hdc = GetDC(nullptr);
+ // Use old DPI value if failed.
+ if (hdc != nullptr) {
Sergey Ulanov 2016/07/28 22:15:32 nit: s/ != nullptr//
Hzj_jie 2016/07/29 02:12:23 Done.
+ dpi_.set(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
+ ReleaseDC(nullptr, hdc);
+ }
+
+ identity_++;
+ return true;
+}
+
+DesktopRect DxgiDuplicatorContainer::ScreenRect(int id) const {
+ RTC_DCHECK(id >= 0);
+ rtc::CritScope lock(&lock_);
+ for (size_t i = 0; i < duplicators_.size(); i++) {
+ if (id >= duplicators_[i].screen_count()) {
+ id -= duplicators_[i].screen_count();
+ } else {
+ return duplicators_[i].ScreenRect(id);
+ }
+ }
+ return DesktopRect();
+}
+
+int DxgiDuplicatorContainer::ScreenCount() const {
+ rtc::CritScope lock(&lock_);
+ int result = 0;
+ for (auto& duplicator : duplicators_) {
+ result += duplicator.screen_count();
+ }
+ return result;
+}
+
+bool DxgiDuplicatorContainer::Duplicate(DxgiContext* context,
+ DesktopFrame* target,
+ const DesktopFrame* last_frame) {
+ RTC_DCHECK(target);
+ if (last_frame != nullptr && !target->size().equals(last_frame->size())) {
Sergey Ulanov 2016/07/28 22:15:32 nit: s/last_frame != nullptr/last_frame/
Sergey Ulanov 2016/07/28 22:15:32 Replace with a DCHECK()
Hzj_jie 2016/07/29 02:12:23 Done.
Hzj_jie 2016/07/29 02:12:23 Returns false here can help consumers to decide wh
+ return false;
+ }
+ target->mutable_updated_region()->Clear();
+ rtc::CritScope lock(&lock_);
+ if (duplicators_.empty() || DxgiContextExpired(context)) {
+ // Next Prepare call will initialize duplicators_ or context.
+ return false;
+ }
+ for (size_t i = 0; i < duplicators_.size(); i++) {
+ if (!duplicators_[i].Duplicate(&context->contexts_[i], target,
+ last_frame)) {
+ Deinitialize();
+ return false;
+ }
+ }
+ target->set_dpi(dpi());
+ return true;
+}
+
+bool DxgiDuplicatorContainer::Duplicate(DxgiContext* context,
Sergey Ulanov 2016/07/28 22:15:32 call this DuplicateScreen()? https://google.github
Hzj_jie 2016/07/29 02:12:23 To match the design doc, changed to DuplicateMonit
+ int id,
Sergey Ulanov 2016/07/28 22:15:32 screen_id?
Hzj_jie 2016/07/29 02:12:23 Done.
+ DesktopFrame* target,
+ const DesktopFrame* last_frame) {
Sergey Ulanov 2016/07/28 22:15:32 swap the last two arguments, see https://google.gi
Hzj_jie 2016/07/29 02:12:23 Order changed, but last_frame may be nullptr.
+ RTC_DCHECK(target);
+ RTC_DCHECK(id >= 0);
+ if (last_frame != nullptr && !target->size().equals(last_frame->size())) {
Sergey Ulanov 2016/07/28 22:15:32 Replace this with a DCHECK.
Hzj_jie 2016/07/29 02:12:23 Same as above.
+ return false;
+ }
+ target->mutable_updated_region()->Clear();
+ rtc::CritScope lock(&lock_);
+ if (duplicators_.empty() || DxgiContextExpired(context)) {
+ // Next Prepare call will initialize duplicators_ or context.
+ return false;
+ }
+ for (size_t i = 0; i < duplicators_.size() && i < context->contexts_.size();
+ i++) {
+ if (id >= duplicators_[i].screen_count()) {
+ id -= duplicators_[i].screen_count();
+ } else {
+ if (duplicators_[i].Duplicate(&context->contexts_[i], id, target,
+ last_frame)) {
+ target->set_dpi(dpi());
+ return true;
+ }
+ Deinitialize();
+ return false;
+ }
+ }
+ // id >= ScreenCount(). This is a user error, so we do not need to
+ // deinitialize.
+ return false;
+}
+
+} // namespace webrtc

Powered by Google App Engine
This is Rietveld 408576698