[ScreenCapturerX11] Fix update-region for monitors with offsets.
This CL ensures that each DesktopFrame's updated-region is expressed in
the frame's own coordinates, where the top-left is always (0, 0).
For example, DesktopFrame::GetFrameDataAtPos() and its callers use
this coordinate system.
Previously, whenever a RANDR monitor with a non-zero offset was
selected, ScreenCapturerX11 would hit some DCHECKs when trying to
copy pixels from previous frames, or when capturing new pixels into
them from XDAMAGE regions.
Bug: None
Change-Id: I7b2e8d0449359ee7b263ad60af193e2bf89aa1f4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/232085
Reviewed-by: Joe Downing <joedow@chromium.org>
Commit-Queue: Joe Downing <joedow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#35017}
diff --git a/modules/desktop_capture/linux/screen_capturer_x11.cc b/modules/desktop_capture/linux/screen_capturer_x11.cc
index ab1bd7f..e05f7bf 100644
--- a/modules/desktop_capture/linux/screen_capturer_x11.cc
+++ b/modules/desktop_capture/linux/screen_capturer_x11.cc
@@ -355,6 +355,7 @@
std::unique_ptr<DesktopFrame> ScreenCapturerX11::CaptureScreen() {
std::unique_ptr<SharedDesktopFrame> frame = queue_.current_frame()->Share();
RTC_DCHECK(selected_monitor_rect_.size().equals(frame->size()));
+ RTC_DCHECK(selected_monitor_rect_.top_left().equals(frame->top_left()));
// Pass the screen size to the helper, so it can clip the invalid region if it
// expands that region to a grid.
@@ -378,19 +379,30 @@
XRectangle* rects = XFixesFetchRegionAndBounds(display(), damage_region_,
&rects_num, &bounds);
for (int i = 0; i < rects_num; ++i) {
- updated_region->AddRect(DesktopRect::MakeXYWH(
- rects[i].x, rects[i].y, rects[i].width, rects[i].height));
+ auto damage_rect = DesktopRect::MakeXYWH(rects[i].x, rects[i].y,
+ rects[i].width, rects[i].height);
+
+ // Damage regions are in the same coordinate-system as
+ // ```selected_monitor_rect_```, but may fall outside of it.
+ damage_rect.IntersectWith(selected_monitor_rect_);
+ if (!damage_rect.is_empty()) {
+ // Convert to DesktopFrame coordinates where the top-left is
+ // always (0, 0), before adding to the frame's update_region.
+ damage_rect.Translate(-frame->top_left());
+ updated_region->AddRect(damage_rect);
+ }
}
XFree(rects);
helper_.InvalidateRegion(*updated_region);
// Capture the damaged portions of the desktop.
helper_.TakeInvalidRegion(updated_region);
- updated_region->IntersectWith(selected_monitor_rect_);
for (DesktopRegion::Iterator it(*updated_region); !it.IsAtEnd();
it.Advance()) {
- if (!x_server_pixel_buffer_.CaptureRect(it.rect(), frame.get()))
+ auto rect = it.rect();
+ rect.Translate(frame->top_left());
+ if (!x_server_pixel_buffer_.CaptureRect(rect, frame.get()))
return nullptr;
}
} else {
@@ -400,7 +412,7 @@
frame.get())) {
return nullptr;
}
- updated_region->SetRect(selected_monitor_rect_);
+ updated_region->SetRect(DesktopRect::MakeSize(frame->size()));
}
return std::move(frame);
@@ -445,11 +457,8 @@
RTC_DCHECK(current != last);
for (DesktopRegion::Iterator it(last_invalid_region_); !it.IsAtEnd();
it.Advance()) {
- if (selected_monitor_rect_.ContainsRect(it.rect())) {
- DesktopRect r = it.rect();
- r.Translate(-selected_monitor_rect_.top_left());
- current->CopyPixelsFrom(*last, r.top_left(), r);
- }
+ const DesktopRect& r = it.rect();
+ current->CopyPixelsFrom(*last, r.top_left(), r);
}
}