Allow specifying GPU adapter LUID for WGC capturer Add d3d_device_luid option to DesktopCaptureOptions so that the WGC capturer can create its D3D11 device on a specific GPU adapter. This is needed for texture sharing with the GPU process when the system has multiple adapters. Bug: chromium:40929600 Change-Id: Ib04e5eb88a0c57f7cf13e984c6f3a96296928d25 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/461040 Reviewed-by: Harald Alvestrand <hta@webrtc.org> Commit-Queue: Wang, Zhibo1 <zhibo1.wang@intel.com> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#47340}
diff --git a/modules/desktop_capture/desktop_capture_options.h b/modules/desktop_capture/desktop_capture_options.h index 3ce4678..9cba039 100644 --- a/modules/desktop_capture/desktop_capture_options.h +++ b/modules/desktop_capture/desktop_capture_options.h
@@ -27,6 +27,10 @@ #include "modules/desktop_capture/mac/desktop_configuration_monitor.h" #endif +#if defined(WEBRTC_WIN) +#include <windows.h> +#endif + #include "modules/desktop_capture/full_screen_window_detector.h" namespace webrtc { @@ -234,6 +238,11 @@ void set_allow_wgc_using_texture(bool allow) { allow_wgc_using_texture_ = allow; } + + // The LUID of the GPU adapter to use for D3D11 device creation in the WGC + // capturer. A zero LUID means use the system default adapter. + LUID d3d_device_luid() const { return d3d_device_luid_; } + void set_d3d_device_luid(LUID luid) { d3d_device_luid_ = luid; } #endif // defined(RTC_ENABLE_WIN_WGC) #endif // defined(WEBRTC_WIN) @@ -293,6 +302,7 @@ bool wgc_require_border_ = false; bool wgc_include_secondary_windows_ = false; bool allow_wgc_using_texture_ = false; + LUID d3d_device_luid_ = {}; #endif #endif #if defined(WEBRTC_USE_X11)
diff --git a/modules/desktop_capture/win/wgc_capturer_win.cc b/modules/desktop_capture/win/wgc_capturer_win.cc index cc9ea52..bdbcda6 100644 --- a/modules/desktop_capture/win/wgc_capturer_win.cc +++ b/modules/desktop_capture/win/wgc_capturer_win.cc
@@ -11,6 +11,7 @@ #include "modules/desktop_capture/win/wgc_capturer_win.h" #include <DispatcherQueue.h> +#include <dxgi1_4.h> #include <windows.foundation.metadata.h> #include <windows.graphics.capture.h> @@ -284,11 +285,28 @@ callback_ = callback; - // Create a Direct3D11 device to share amongst the WgcCaptureSessions. Many - // parameters are nullptr as the implemention uses defaults that work well for - // us. - HRESULT hr = D3D11CreateDevice( - /*adapter=*/nullptr, D3D_DRIVER_TYPE_HARDWARE, + // Create a Direct3D11 device to share amongst the WgcCaptureSessions. + // When a specific GPU adapter LUID is provided (e.g. for texture sharing with + // the GPU process), create the device on that adapter. Otherwise, fall back + // to the system default adapter. + HRESULT hr; + ComPtr<IDXGIAdapter> adapter; + const LUID luid = options_.d3d_device_luid(); + if (luid.LowPart != 0 || luid.HighPart != 0) { + ComPtr<IDXGIFactory4> factory4; + hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory4)); + if (SUCCEEDED(hr)) { + hr = factory4->EnumAdapterByLuid(luid, IID_PPV_ARGS(&adapter)); + } + if (FAILED(hr)) { + RTC_LOG(LS_WARNING) << "Failed to get adapter by LUID, " + << "falling back to default adapter: " << hr; + } + } + + hr = D3D11CreateDevice( + adapter.Get(), + adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, /*software_rasterizer=*/nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, /*feature_levels=*/nullptr, /*feature_levels_size=*/0, D3D11_SDK_VERSION, &d3d11_device_, /*feature_level=*/nullptr, /*device_context=*/nullptr);
diff --git a/modules/desktop_capture/win/wgc_capturer_win_unittest.cc b/modules/desktop_capture/win/wgc_capturer_win_unittest.cc index 8119c70..2048eb2 100644 --- a/modules/desktop_capture/win/wgc_capturer_win_unittest.cc +++ b/modules/desktop_capture/win/wgc_capturer_win_unittest.cc
@@ -10,6 +10,9 @@ #include "modules/desktop_capture/win/wgc_capturer_win.h" +#include <dxgi.h> +#include <wrl/client.h> + #include <algorithm> #include <cstddef> #include <cstdint> @@ -100,6 +103,22 @@ } // namespace +class LogMessageMatcher : public LogSink { + public: + explicit LogMessageMatcher(const std::string& substring) + : substring_(substring) {} + bool matched() const { return matched_; } + + private: + void OnLogMessage(const std::string& message) override { + if (message.find(substring_) != std::string::npos) { + matched_ = true; + } + } + std::string substring_; + bool matched_ = false; +}; + class WgcCapturerWinTest : public ::testing::TestWithParam<CaptureType>, public DesktopCapturer::Callback { public: @@ -124,9 +143,9 @@ source_id_ = GetTestWindowIdFromSourceList(); } - void SetUpForScreenCapture() { - capturer_ = WgcCapturerWin::CreateRawScreenCapturer( - DesktopCaptureOptions::CreateDefault()); + void SetUpForScreenCapture(const DesktopCaptureOptions& options = + DesktopCaptureOptions::CreateDefault()) { + capturer_ = WgcCapturerWin::CreateRawScreenCapturer(options); source_id_ = GetScreenIdFromSourceList(); } @@ -419,6 +438,56 @@ EXPECT_GT(frame_->size().height(), 0); } +TEST_F(WgcCapturerMonitorTest, CaptureWithValidAdapterLuid) { + // Get the LUID of the first DXGI adapter on the system. + Microsoft::WRL::ComPtr<IDXGIFactory1> factory; + ASSERT_TRUE(SUCCEEDED(CreateDXGIFactory1(IID_PPV_ARGS(&factory)))); + Microsoft::WRL::ComPtr<IDXGIAdapter> adapter; + ASSERT_TRUE(SUCCEEDED(factory->EnumAdapters(0, &adapter))); + DXGI_ADAPTER_DESC desc; + ASSERT_TRUE(SUCCEEDED(adapter->GetDesc(&desc))); + + LogMessageMatcher fallback_matcher("Failed to get adapter by LUID"); + LogMessage::AddLogToStream(&fallback_matcher, LS_WARNING); + + DesktopCaptureOptions options = DesktopCaptureOptions::CreateDefault(); + options.set_d3d_device_luid(desc.AdapterLuid); + SetUpForScreenCapture(options); + EXPECT_TRUE(capturer_->SelectSource(kFullDesktopScreenId)); + + capturer_->Start(this); + + LogMessage::RemoveLogToStream(&fallback_matcher); + EXPECT_FALSE(fallback_matcher.matched()); + + DoCapture(); + EXPECT_GT(frame_->size().width(), 0); + EXPECT_GT(frame_->size().height(), 0); +} + +TEST_F(WgcCapturerMonitorTest, CaptureWithInvalidAdapterLuid) { + // Use a non-zero but invalid LUID. The capturer should fall back to the + // default adapter and still capture successfully. + LUID invalid_luid = {0xFFFF, 0x7FFF}; + + LogMessageMatcher fallback_matcher("falling back to default adapter"); + LogMessage::AddLogToStream(&fallback_matcher, LS_WARNING); + + DesktopCaptureOptions options = DesktopCaptureOptions::CreateDefault(); + options.set_d3d_device_luid(invalid_luid); + SetUpForScreenCapture(options); + EXPECT_TRUE(capturer_->SelectSource(kFullDesktopScreenId)); + + capturer_->Start(this); + + LogMessage::RemoveLogToStream(&fallback_matcher); + EXPECT_TRUE(fallback_matcher.matched()); + + DoCapture(); + EXPECT_GT(frame_->size().width(), 0); + EXPECT_GT(frame_->size().height(), 0); +} + class WgcCapturerWindowTest : public WgcCapturerWinTest { public: void SetUp() {