Add reference counter of DxgiDuplicatorController to unload DXGI components

On Windows, only four applications can use DXGI duplication APIs concurrently.
So this change adds a reference counter of DxgiDuplicatorController to unload
DXGI components when the reference counter reaches 0.

BUG=webrtc:7808

Review-Url: https://codereview.webrtc.org/2933893003
Cr-Commit-Position: refs/heads/master@{#18668}
This commit is contained in:
zijiehe 2017-06-19 13:59:42 -07:00 committed by Commit Bot
parent a87675d4a1
commit 6dd77c4d89
5 changed files with 67 additions and 30 deletions

View File

@ -24,10 +24,9 @@ namespace webrtc {
namespace {
std::unique_ptr<DesktopCapturer> CreateScreenCapturerWinDirectx(
const DesktopCaptureOptions& options) {
std::unique_ptr<DesktopCapturer> CreateScreenCapturerWinDirectx() {
std::unique_ptr<DesktopCapturer> capturer(
new ScreenCapturerWinDirectx(options));
new ScreenCapturerWinDirectx());
capturer.reset(new BlankDetectorDesktopCapturerWrapper(
std::move(capturer), RgbaColor(0, 0, 0, 0)));
return capturer;
@ -39,10 +38,14 @@ std::unique_ptr<DesktopCapturer> CreateScreenCapturerWinDirectx(
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawScreenCapturer(
const DesktopCaptureOptions& options) {
std::unique_ptr<DesktopCapturer> capturer(new ScreenCapturerWinGdi(options));
if (options.allow_directx_capturer() &&
ScreenCapturerWinDirectx::IsSupported()) {
capturer.reset(new FallbackDesktopCapturerWrapper(
CreateScreenCapturerWinDirectx(options), std::move(capturer)));
if (options.allow_directx_capturer()) {
// |dxgi_duplicator_controller| should be alive in this scope to ensure it
// won't unload DxgiDuplicatorController.
auto dxgi_duplicator_controller = DxgiDuplicatorController::Instance();
if (ScreenCapturerWinDirectx::IsSupported()) {
capturer.reset(new FallbackDesktopCapturerWrapper(
CreateScreenCapturerWinDirectx(), std::move(capturer)));
}
}
if (options.allow_use_magnification_api()) {

View File

@ -16,6 +16,7 @@
#include <string>
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/modules/desktop_capture/desktop_capture_types.h"
#include "webrtc/modules/desktop_capture/win/dxgi_frame.h"
@ -25,18 +26,30 @@
namespace webrtc {
// static
DxgiDuplicatorController* DxgiDuplicatorController::Instance() {
rtc::scoped_refptr<DxgiDuplicatorController>
DxgiDuplicatorController::Instance() {
// The static instance won't be deleted to ensure it can be used by other
// threads even during program exiting.
static DxgiDuplicatorController* instance = new DxgiDuplicatorController();
return instance;
return rtc::scoped_refptr<DxgiDuplicatorController>(instance);
}
DxgiDuplicatorController::DxgiDuplicatorController() = default;
DxgiDuplicatorController::DxgiDuplicatorController()
: refcount_(0) {}
DxgiDuplicatorController::~DxgiDuplicatorController() {
rtc::CritScope lock(&lock_);
Deinitialize();
void DxgiDuplicatorController::AddRef() {
int refcount = (++refcount_);
RTC_DCHECK(refcount > 0);
}
void DxgiDuplicatorController::Release() {
int refcount = (--refcount_);
RTC_DCHECK(refcount >= 0);
if (refcount == 0) {
LOG(LS_WARNING) << "Count of references reaches zero, "
"DxgiDuplicatorController will be unloaded.";
Unload();
}
}
bool DxgiDuplicatorController::IsSupported() {
@ -129,6 +142,11 @@ DxgiDuplicatorController::DoDuplicate(DxgiFrame* frame, int monitor_id) {
return Result::DUPLICATION_FAILED;
}
void DxgiDuplicatorController::Unload() {
rtc::CritScope lock(&lock_);
Deinitialize();
}
void DxgiDuplicatorController::Unregister(const Context* const context) {
rtc::CritScope lock(&lock_);
if (ContextExpired(context)) {

View File

@ -13,10 +13,11 @@
#include <D3DCommon.h>
#include <memory>
#include <atomic>
#include <vector>
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/scoped_ref_ptr.h"
#include "webrtc/modules/desktop_capture/desktop_geometry.h"
#include "webrtc/modules/desktop_capture/resolution_change_detector.h"
#include "webrtc/modules/desktop_capture/shared_desktop_frame.h"
@ -66,12 +67,7 @@ class DxgiDuplicatorController {
};
// Returns the singleton instance of DxgiDuplicatorController.
static DxgiDuplicatorController* Instance();
// Destructs current instance. We need to make sure COM components and their
// containers are destructed in correct order. This function calls
// Deinitialize() to do the real work.
~DxgiDuplicatorController();
static rtc::scoped_refptr<DxgiDuplicatorController> Instance();
// All the following public functions implicitly call Initialize() function.
@ -107,16 +103,32 @@ class DxgiDuplicatorController {
// destructing.
friend DxgiFrameContext::~DxgiFrameContext();
// scoped_refptr<DxgiDuplicatorController> accesses private AddRef() and
// Release() functions.
friend class rtc::scoped_refptr<DxgiDuplicatorController>;
// A private constructor to ensure consumers to use
// DxgiDuplicatorController::Instance().
DxgiDuplicatorController();
// Not implemented: The singleton DxgiDuplicatorController instance should not
// be deleted.
~DxgiDuplicatorController();
// RefCountedInterface implementations.
void AddRef();
void Release();
// Does the real duplication work. Setting |monitor_id| < 0 to capture entire
// screen. This function calls Initialize(). And if the duplication failed,
// this function calls Deinitialize() to ensure the Dxgi components can be
// reinitialized next time.
Result DoDuplicate(DxgiFrame* frame, int monitor_id);
// Unload all the DXGI components and releases the resources. This function
// wraps Deinitialize() with |lock_|.
void Unload();
// Unregisters Context from this instance and all DxgiAdapterDuplicator(s)
// it owns.
void Unregister(const Context* const context);
@ -185,6 +197,9 @@ class DxgiDuplicatorController {
// DxgiAdapterDuplicator and DxgiOutputDuplicator instances are initialized.
void TranslateRect();
// The count of references which are now "living".
std::atomic_int refcount_;
// This lock must be locked whenever accessing any of the following objects.
rtc::CriticalSection lock_;

View File

@ -36,11 +36,10 @@ bool ScreenCapturerWinDirectx::RetrieveD3dInfo(D3dInfo* info) {
return DxgiDuplicatorController::Instance()->RetrieveD3dInfo(info);
}
ScreenCapturerWinDirectx::ScreenCapturerWinDirectx(
const DesktopCaptureOptions& options)
: callback_(nullptr) {}
ScreenCapturerWinDirectx::ScreenCapturerWinDirectx()
: controller_(DxgiDuplicatorController::Instance()) {}
ScreenCapturerWinDirectx::~ScreenCapturerWinDirectx() {}
ScreenCapturerWinDirectx::~ScreenCapturerWinDirectx() = default;
void ScreenCapturerWinDirectx::Start(Callback* callback) {
RTC_DCHECK(!callback_);
@ -67,10 +66,9 @@ void ScreenCapturerWinDirectx::CaptureFrame() {
DxgiDuplicatorController::Result result;
if (current_screen_id_ == kFullDesktopScreenId) {
result = DxgiDuplicatorController::Instance()->Duplicate(
frames_.current_frame());
result = controller_->Duplicate(frames_.current_frame());
} else {
result = DxgiDuplicatorController::Instance()->DuplicateMonitor(
result = controller_->DuplicateMonitor(
frames_.current_frame(), current_screen_id_);
}
@ -106,7 +104,7 @@ void ScreenCapturerWinDirectx::CaptureFrame() {
}
bool ScreenCapturerWinDirectx::GetSourceList(SourceList* sources) {
int screen_count = DxgiDuplicatorController::Instance()->ScreenCount();
int screen_count = controller_->ScreenCount();
for (int i = 0; i < screen_count; i++) {
sources->push_back({i});
}
@ -123,7 +121,7 @@ bool ScreenCapturerWinDirectx::SelectSource(SourceId id) {
return true;
}
int screen_count = DxgiDuplicatorController::Instance()->ScreenCount();
int screen_count = controller_->ScreenCount();
if (id >= 0 && id < screen_count) {
current_screen_id_ = id;
return true;

View File

@ -16,6 +16,7 @@
#include <memory>
#include <vector>
#include "webrtc/base/scoped_ref_ptr.h"
#include "webrtc/modules/desktop_capture/desktop_capturer.h"
#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "webrtc/modules/desktop_capture/desktop_region.h"
@ -43,10 +44,11 @@ class ScreenCapturerWinDirectx : public DesktopCapturer {
// consumers should not cache the result returned by this function.
static bool RetrieveD3dInfo(D3dInfo* info);
explicit ScreenCapturerWinDirectx(const DesktopCaptureOptions& options);
explicit ScreenCapturerWinDirectx();
~ScreenCapturerWinDirectx() override;
// DesktopCapturer implementation.
void Start(Callback* callback) override;
void SetSharedMemoryFactory(
std::unique_ptr<SharedMemoryFactory> shared_memory_factory) override;
@ -55,6 +57,7 @@ class ScreenCapturerWinDirectx : public DesktopCapturer {
bool SelectSource(SourceId id) override;
private:
const rtc::scoped_refptr<DxgiDuplicatorController> controller_;
ScreenCaptureFrameQueue<DxgiFrame> frames_;
std::unique_ptr<SharedMemoryFactory> shared_memory_factory_;
Callback* callback_ = nullptr;