[DesktopCapture][WGC] Avoid artifacts when capture source is resized
This CL fixes the issue where artifacts appear during capture with WGC when the capture source is resized. A video of the issue is available here: https://bugs.chromium.org/p/webrtc/issues/detail?id=9273#c44 The solution is to use CopySubresourceRegion instead of CopyResource to only copy valid data into our texture. Additionally, we moved the call to CreateMappedTexture to before the call to CopySubresourceRegion, as the latter requires both textures to be of the same size. Bug: webrtc:9273 Change-Id: I114458d95cbf58550ff653a985dd84db4741e0f8 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/254100 Reviewed-by: Alexander Cooper <alcooper@chromium.org> Commit-Queue: Austin Orion <auorion@microsoft.com> Cr-Commit-Position: refs/heads/main@{#36163}
This commit is contained in:

committed by
WebRTC LUCI CQ

parent
878c0299b3
commit
a5f3018c24
@ -223,8 +223,8 @@ HRESULT WgcCaptureSession::GetFrame(
|
||||
return hr;
|
||||
}
|
||||
|
||||
// We need to get this CaptureFrame as an ID3D11Texture2D so that we can get
|
||||
// the raw image data in the format required by the DesktopFrame interface.
|
||||
// We need to get `capture_frame` as an `ID3D11Texture2D` so that we can get
|
||||
// the raw image data in the format required by the `DesktopFrame` interface.
|
||||
ComPtr<ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface>
|
||||
d3d_surface;
|
||||
hr = capture_frame->get_Surface(&d3d_surface);
|
||||
@ -261,16 +261,6 @@ HRESULT WgcCaptureSession::GetFrame(
|
||||
// Otherwise it would only be readable by the GPU.
|
||||
ComPtr<ID3D11DeviceContext> d3d_context;
|
||||
d3d11_device_->GetImmediateContext(&d3d_context);
|
||||
d3d_context->CopyResource(mapped_texture_.Get(), texture_2D.Get());
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE map_info;
|
||||
hr = d3d_context->Map(mapped_texture_.Get(), /*subresource_index=*/0,
|
||||
D3D11_MAP_READ, /*D3D11_MAP_FLAG_DO_NOT_WAIT=*/0,
|
||||
&map_info);
|
||||
if (FAILED(hr)) {
|
||||
RecordGetFrameResult(GetFrameResult::kMapFrameFailed);
|
||||
return hr;
|
||||
}
|
||||
|
||||
ABI::Windows::Graphics::SizeInt32 new_size;
|
||||
hr = capture_frame->get_ContentSize(&new_size);
|
||||
@ -279,34 +269,9 @@ HRESULT WgcCaptureSession::GetFrame(
|
||||
return hr;
|
||||
}
|
||||
|
||||
// If the size has changed since the last capture, we must be sure to use
|
||||
// the smaller dimensions. Otherwise we might overrun our buffer, or
|
||||
// read stale data from the last frame.
|
||||
int image_height = std::min(previous_size_.Height, new_size.Height);
|
||||
int image_width = std::min(previous_size_.Width, new_size.Width);
|
||||
int row_data_length = image_width * DesktopFrame::kBytesPerPixel;
|
||||
|
||||
// Make a copy of the data pointed to by `map_info.pData` so we are free to
|
||||
// unmap our texture.
|
||||
uint8_t* src_data = static_cast<uint8_t*>(map_info.pData);
|
||||
std::vector<uint8_t> image_data;
|
||||
image_data.resize(image_height * row_data_length);
|
||||
uint8_t* image_data_ptr = image_data.data();
|
||||
for (int i = 0; i < image_height; i++) {
|
||||
memcpy(image_data_ptr, src_data, row_data_length);
|
||||
image_data_ptr += row_data_length;
|
||||
src_data += map_info.RowPitch;
|
||||
}
|
||||
|
||||
// Transfer ownership of `image_data` to the output_frame.
|
||||
DesktopSize size(image_width, image_height);
|
||||
*output_frame = std::make_unique<WgcDesktopFrame>(size, row_data_length,
|
||||
std::move(image_data));
|
||||
|
||||
d3d_context->Unmap(mapped_texture_.Get(), 0);
|
||||
|
||||
// If the size changed, we must resize the texture and frame pool to fit the
|
||||
// new size.
|
||||
// If the size changed, we must resize `mapped_texture_` and `frame_pool_` to
|
||||
// fit the new size. This must be done before `CopySubresourceRegion` so that
|
||||
// the textures are the same size.
|
||||
if (previous_size_.Height != new_size.Height ||
|
||||
previous_size_.Width != new_size.Width) {
|
||||
hr = CreateMappedTexture(texture_2D, new_size.Width, new_size.Height);
|
||||
@ -323,9 +288,57 @@ HRESULT WgcCaptureSession::GetFrame(
|
||||
}
|
||||
}
|
||||
|
||||
RecordGetFrameResult(GetFrameResult::kSuccess);
|
||||
// If the size has changed since the last capture, we must be sure to use
|
||||
// the smaller dimensions. Otherwise we might overrun our buffer, or
|
||||
// read stale data from the last frame.
|
||||
int image_height = std::min(previous_size_.Height, new_size.Height);
|
||||
int image_width = std::min(previous_size_.Width, new_size.Width);
|
||||
|
||||
D3D11_BOX copy_region;
|
||||
copy_region.left = 0;
|
||||
copy_region.top = 0;
|
||||
copy_region.right = image_width;
|
||||
copy_region.bottom = image_height;
|
||||
// Our textures are 2D so we just want one "slice" of the box.
|
||||
copy_region.front = 0;
|
||||
copy_region.back = 1;
|
||||
d3d_context->CopySubresourceRegion(mapped_texture_.Get(),
|
||||
/*dst_subresource_index=*/0, /*dst_x=*/0,
|
||||
/*dst_y=*/0, /*dst_z=*/0, texture_2D.Get(),
|
||||
/*src_subresource_index=*/0, ©_region);
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE map_info;
|
||||
hr = d3d_context->Map(mapped_texture_.Get(), /*subresource_index=*/0,
|
||||
D3D11_MAP_READ, /*D3D11_MAP_FLAG_DO_NOT_WAIT=*/0,
|
||||
&map_info);
|
||||
if (FAILED(hr)) {
|
||||
RecordGetFrameResult(GetFrameResult::kMapFrameFailed);
|
||||
return hr;
|
||||
}
|
||||
|
||||
int row_data_length = image_width * DesktopFrame::kBytesPerPixel;
|
||||
|
||||
// Make a copy of the data pointed to by `map_info.pData` so we are free to
|
||||
// unmap our texture.
|
||||
uint8_t* src_data = static_cast<uint8_t*>(map_info.pData);
|
||||
std::vector<uint8_t> image_data;
|
||||
image_data.resize(image_height * row_data_length);
|
||||
uint8_t* image_data_ptr = image_data.data();
|
||||
for (int i = 0; i < image_height; i++) {
|
||||
memcpy(image_data_ptr, src_data, row_data_length);
|
||||
image_data_ptr += row_data_length;
|
||||
src_data += map_info.RowPitch;
|
||||
}
|
||||
|
||||
d3d_context->Unmap(mapped_texture_.Get(), 0);
|
||||
|
||||
// Transfer ownership of `image_data` to the output_frame.
|
||||
DesktopSize size(image_width, image_height);
|
||||
*output_frame = std::make_unique<WgcDesktopFrame>(size, row_data_length,
|
||||
std::move(image_data));
|
||||
|
||||
previous_size_ = new_size;
|
||||
RecordGetFrameResult(GetFrameResult::kSuccess);
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user