tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

dxgi_adapter_duplicator.cc (6893B)


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