xref: /aosp_15_r20/external/webrtc/modules/desktop_capture/win/dxgi_adapter_duplicator.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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 "modules/desktop_capture/win/dxgi_adapter_duplicator.h"
12 
13 #include <comdef.h>
14 #include <dxgi.h>
15 
16 #include <algorithm>
17 
18 #include "modules/desktop_capture/win/desktop_capture_utils.h"
19 #include "rtc_base/checks.h"
20 #include "rtc_base/logging.h"
21 
22 namespace webrtc {
23 
24 using Microsoft::WRL::ComPtr;
25 
26 namespace {
27 
IsValidRect(const RECT & rect)28 bool IsValidRect(const RECT& rect) {
29   return rect.right > rect.left && rect.bottom > rect.top;
30 }
31 
32 }  // namespace
33 
DxgiAdapterDuplicator(const D3dDevice & device)34 DxgiAdapterDuplicator::DxgiAdapterDuplicator(const D3dDevice& device)
35     : device_(device) {}
36 DxgiAdapterDuplicator::DxgiAdapterDuplicator(DxgiAdapterDuplicator&&) = default;
37 DxgiAdapterDuplicator::~DxgiAdapterDuplicator() = default;
38 
Initialize()39 bool DxgiAdapterDuplicator::Initialize() {
40   if (DoInitialize()) {
41     return true;
42   }
43   duplicators_.clear();
44   return false;
45 }
46 
DoInitialize()47 bool DxgiAdapterDuplicator::DoInitialize() {
48   for (int i = 0;; i++) {
49     ComPtr<IDXGIOutput> output;
50     _com_error error =
51         device_.dxgi_adapter()->EnumOutputs(i, output.GetAddressOf());
52     if (error.Error() == DXGI_ERROR_NOT_FOUND) {
53       break;
54     }
55 
56     if (error.Error() == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
57       RTC_LOG(LS_WARNING) << "IDXGIAdapter::EnumOutputs returned "
58                           << "NOT_CURRENTLY_AVAILABLE. This may happen when "
59                           << "running in session 0.";
60       break;
61     }
62 
63     if (error.Error() != S_OK || !output) {
64       RTC_LOG(LS_WARNING) << "IDXGIAdapter::EnumOutputs returned an unexpected "
65                           << "result: "
66                           << desktop_capture::utils::ComErrorToString(error);
67       continue;
68     }
69 
70     DXGI_OUTPUT_DESC desc;
71     error = output->GetDesc(&desc);
72     if (error.Error() == S_OK) {
73       if (desc.AttachedToDesktop && IsValidRect(desc.DesktopCoordinates)) {
74         ComPtr<IDXGIOutput1> output1;
75         error = output.As(&output1);
76         if (error.Error() != S_OK || !output1) {
77           RTC_LOG(LS_WARNING)
78               << "Failed to convert IDXGIOutput to IDXGIOutput1, this usually "
79               << "means the system does not support DirectX 11";
80           continue;
81         }
82         DxgiOutputDuplicator duplicator(device_, output1, desc);
83         if (!duplicator.Initialize()) {
84           RTC_LOG(LS_WARNING) << "Failed to initialize DxgiOutputDuplicator on "
85                               << "output " << i;
86           continue;
87         }
88 
89         duplicators_.push_back(std::move(duplicator));
90         desktop_rect_.UnionWith(duplicators_.back().desktop_rect());
91       } else {
92         RTC_LOG(LS_ERROR) << (desc.AttachedToDesktop ? "Attached" : "Detached")
93                           << " output " << i << " ("
94                           << desc.DesktopCoordinates.top << ", "
95                           << desc.DesktopCoordinates.left << ") - ("
96                           << desc.DesktopCoordinates.bottom << ", "
97                           << desc.DesktopCoordinates.right << ") is ignored.";
98       }
99     } else {
100       RTC_LOG(LS_WARNING) << "Failed to get output description of device " << i
101                           << ", ignore.";
102     }
103   }
104 
105   if (duplicators_.empty()) {
106     RTC_LOG(LS_WARNING)
107         << "Cannot initialize any DxgiOutputDuplicator instance.";
108   }
109 
110   return !duplicators_.empty();
111 }
112 
Setup(Context * context)113 void DxgiAdapterDuplicator::Setup(Context* context) {
114   RTC_DCHECK(context->contexts.empty());
115   context->contexts.resize(duplicators_.size());
116   for (size_t i = 0; i < duplicators_.size(); i++) {
117     duplicators_[i].Setup(&context->contexts[i]);
118   }
119 }
120 
Unregister(const Context * const context)121 void DxgiAdapterDuplicator::Unregister(const Context* const context) {
122   RTC_DCHECK_EQ(context->contexts.size(), duplicators_.size());
123   for (size_t i = 0; i < duplicators_.size(); i++) {
124     duplicators_[i].Unregister(&context->contexts[i]);
125   }
126 }
127 
Duplicate(Context * context,SharedDesktopFrame * target)128 bool DxgiAdapterDuplicator::Duplicate(Context* context,
129                                       SharedDesktopFrame* target) {
130   RTC_DCHECK_EQ(context->contexts.size(), duplicators_.size());
131   for (size_t i = 0; i < duplicators_.size(); i++) {
132     if (!duplicators_[i].Duplicate(&context->contexts[i],
133                                    duplicators_[i].desktop_rect().top_left(),
134                                    target)) {
135       return false;
136     }
137   }
138   return true;
139 }
140 
DuplicateMonitor(Context * context,int monitor_id,SharedDesktopFrame * target)141 bool DxgiAdapterDuplicator::DuplicateMonitor(Context* context,
142                                              int monitor_id,
143                                              SharedDesktopFrame* target) {
144   RTC_DCHECK_GE(monitor_id, 0);
145   RTC_DCHECK_LT(monitor_id, duplicators_.size());
146   RTC_DCHECK_EQ(context->contexts.size(), duplicators_.size());
147   return duplicators_[monitor_id].Duplicate(&context->contexts[monitor_id],
148                                             DesktopVector(), target);
149 }
150 
ScreenRect(int id) const151 DesktopRect DxgiAdapterDuplicator::ScreenRect(int id) const {
152   RTC_DCHECK_GE(id, 0);
153   RTC_DCHECK_LT(id, duplicators_.size());
154   return duplicators_[id].desktop_rect();
155 }
156 
GetDeviceName(int id) const157 const std::string& DxgiAdapterDuplicator::GetDeviceName(int id) const {
158   RTC_DCHECK_GE(id, 0);
159   RTC_DCHECK_LT(id, duplicators_.size());
160   return duplicators_[id].device_name();
161 }
162 
screen_count() const163 int DxgiAdapterDuplicator::screen_count() const {
164   return static_cast<int>(duplicators_.size());
165 }
166 
GetNumFramesCaptured() const167 int64_t DxgiAdapterDuplicator::GetNumFramesCaptured() const {
168   int64_t min = INT64_MAX;
169   for (const auto& duplicator : duplicators_) {
170     min = std::min(min, duplicator.num_frames_captured());
171   }
172 
173   return min;
174 }
175 
TranslateRect(const DesktopVector & position)176 void DxgiAdapterDuplicator::TranslateRect(const DesktopVector& position) {
177   desktop_rect_.Translate(position);
178   RTC_DCHECK_GE(desktop_rect_.left(), 0);
179   RTC_DCHECK_GE(desktop_rect_.top(), 0);
180   for (auto& duplicator : duplicators_) {
181     duplicator.TranslateRect(position);
182   }
183 }
184 
185 }  // namespace webrtc
186