Bug 1053264 - Do not use CAPTUREBLT when Desktop Composition is enabled. r=jimm, a=lmandel
authorGian-Carlo Pascutto <gpascutto>
Mon, 01 Sep 2014 10:10:00 +0200
changeset 216700 5638564e0d94
parent 216699 7b689c3657e4
child 216701 18ba9aece9bd
push id3883
push userryanvm@gmail.com
push date2014-09-11 20:34 +0000
treeherdermozilla-beta@d4082d3a082c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm, lmandel
bugs1053264
milestone33.0
Bug 1053264 - Do not use CAPTUREBLT when Desktop Composition is enabled. r=jimm, a=lmandel
media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_win.cc
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_win.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_win.cc
@@ -32,16 +32,17 @@ namespace webrtc {
 
 namespace {
 
 // Constants from dwmapi.h.
 const UINT DWM_EC_DISABLECOMPOSITION = 0;
 const UINT DWM_EC_ENABLECOMPOSITION = 1;
 
 typedef HRESULT (WINAPI * DwmEnableCompositionFunc)(UINT);
+typedef HRESULT (WINAPI * DwmIsCompositionEnabledFunc)(BOOL*);
 
 const wchar_t kDwmapiLibraryName[] = L"dwmapi.dll";
 
 // ScreenCapturerWin captures 32bit RGB using GDI.
 //
 // ScreenCapturerWin is double-buffered as required by ScreenCapturer.
 class ScreenCapturerWin : public ScreenCapturer {
  public:
@@ -97,53 +98,60 @@ class ScreenCapturerWin : public ScreenC
   // Rectangle describing the bounds of the desktop device context.
   DesktopRect desktop_dc_rect_;
 
   // Class to calculate the difference between two screen bitmaps.
   scoped_ptr<Differ> differ_;
 
   HMODULE dwmapi_library_;
   DwmEnableCompositionFunc composition_func_;
+  DwmIsCompositionEnabledFunc composition_enabled_func_;
+
+  bool disable_composition_;
 
   // Used to suppress duplicate logging of SetThreadExecutionState errors.
   bool set_thread_execution_state_failed_;
 
   DISALLOW_COPY_AND_ASSIGN(ScreenCapturerWin);
 };
 
 ScreenCapturerWin::ScreenCapturerWin(const DesktopCaptureOptions& options)
     : callback_(NULL),
       mouse_shape_observer_(NULL),
       current_screen_id_(kFullDesktopScreenId),
       desktop_dc_(NULL),
       memory_dc_(NULL),
       dwmapi_library_(NULL),
       composition_func_(NULL),
       set_thread_execution_state_failed_(false) {
-  if (options.disable_effects()) {
-    // Load dwmapi.dll dynamically since it is not available on XP.
-    if (!dwmapi_library_)
-      dwmapi_library_ = LoadLibrary(kDwmapiLibraryName);
+  // Load dwmapi.dll dynamically since it is not available on XP.
+  if (!dwmapi_library_)
+    dwmapi_library_ = LoadLibrary(kDwmapiLibraryName);
 
-    if (dwmapi_library_) {
-      composition_func_ = reinterpret_cast<DwmEnableCompositionFunc>(
-          GetProcAddress(dwmapi_library_, "DwmEnableComposition"));
-    }
+  if (dwmapi_library_) {
+    composition_func_ = reinterpret_cast<DwmEnableCompositionFunc>(
+      GetProcAddress(dwmapi_library_, "DwmEnableComposition"));
+    composition_enabled_func_ = reinterpret_cast<DwmIsCompositionEnabledFunc>
+      (GetProcAddress(dwmapi_library_, "DwmIsCompositionEnabled"));
   }
+
+  disable_composition_ = options.disable_effects();
 }
 
 ScreenCapturerWin::~ScreenCapturerWin() {
   if (desktop_dc_)
     ReleaseDC(NULL, desktop_dc_);
   if (memory_dc_)
     DeleteDC(memory_dc_);
 
-  // Restore Aero.
-  if (composition_func_)
-    (*composition_func_)(DWM_EC_ENABLECOMPOSITION);
+  if (disable_composition_) {
+    // Restore Aero.
+    if (composition_func_)
+      (*composition_func_)(DWM_EC_ENABLECOMPOSITION);
+  }
 
   if (dwmapi_library_)
     FreeLibrary(dwmapi_library_);
 }
 
 void ScreenCapturerWin::Capture(const DesktopRegion& region) {
   TickTime capture_start_time = TickTime::Now();
 
@@ -256,21 +264,23 @@ bool ScreenCapturerWin::SelectScreen(Scr
 }
 
 void ScreenCapturerWin::Start(Callback* callback) {
   assert(!callback_);
   assert(callback);
 
   callback_ = callback;
 
-  // Vote to disable Aero composited desktop effects while capturing. Windows
-  // will restore Aero automatically if the process exits. This has no effect
-  // under Windows 8 or higher.  See crbug.com/124018.
-  if (composition_func_)
-    (*composition_func_)(DWM_EC_DISABLECOMPOSITION);
+  if (disable_composition_) {
+    // Vote to disable Aero composited desktop effects while capturing. Windows
+    // will restore Aero automatically if the process exits. This has no effect
+    // under Windows 8 or higher.  See crbug.com/124018.
+    if (composition_func_)
+      (*composition_func_)(DWM_EC_DISABLECOMPOSITION);
+  }
 }
 
 void ScreenCapturerWin::PrepareCaptureResources() {
   // Switch to the desktop receiving user input if different from the current
   // one.
   scoped_ptr<Desktop> input_desktop(Desktop::GetInputDesktop());
   if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) {
     // Release GDI resources otherwise SetThreadDesktop will fail.
@@ -283,20 +293,22 @@ void ScreenCapturerWin::PrepareCaptureRe
       DeleteDC(memory_dc_);
       memory_dc_ = NULL;
     }
 
     // If SetThreadDesktop() fails, the thread is still assigned a desktop.
     // So we can continue capture screen bits, just from the wrong desktop.
     desktop_.SetThreadDesktop(input_desktop.release());
 
-    // Re-assert our vote to disable Aero.
-    // See crbug.com/124018 and crbug.com/129906.
-    if (composition_func_ != NULL) {
-      (*composition_func_)(DWM_EC_DISABLECOMPOSITION);
+    if (disable_composition_) {
+      // Re-assert our vote to disable Aero.
+      // See crbug.com/124018 and crbug.com/129906.
+      if (composition_func_ != NULL) {
+        (*composition_func_)(DWM_EC_DISABLECOMPOSITION);
+      }
     }
   }
 
   // If the display bounds have changed then recreate GDI resources.
   // TODO(wez): Also check for pixel format changes.
   DesktopRect screen_rect(DesktopRect::MakeXYWH(
       GetSystemMetrics(SM_XVIRTUALSCREEN),
       GetSystemMetrics(SM_YVIRTUALSCREEN),
@@ -355,22 +367,34 @@ bool ScreenCapturerWin::CaptureImage() {
     queue_.ReplaceCurrentFrame(buffer.release());
   }
 
   // Select the target bitmap into the memory dc and copy the rect from desktop
   // to memory.
   DesktopFrameWin* current = static_cast<DesktopFrameWin*>(
       queue_.current_frame()->GetUnderlyingFrame());
   HGDIOBJ previous_object = SelectObject(memory_dc_, current->bitmap());
+  DWORD rop = SRCCOPY;
+  if (composition_enabled_func_) {
+    BOOL enabled;
+    (*composition_enabled_func_)(&enabled);
+    if (!enabled) {
+      // Vista or Windows 7, Aero disabled
+      rop |= CAPTUREBLT;
+    }
+  } else {
+    // Windows XP, required to get layered windows
+    rop |= CAPTUREBLT;
+  }
   if (previous_object != NULL) {
     BitBlt(memory_dc_,
            0, 0, screen_rect.width(), screen_rect.height(),
            desktop_dc_,
            screen_rect.left(), screen_rect.top(),
-           SRCCOPY | CAPTUREBLT);
+           rop);
 
     // Select back the previously selected object to that the device contect
     // could be destroyed independently of the bitmap if needed.
     SelectObject(memory_dc_, previous_object);
   }
   return true;
 }