/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/desktop_capture/win/dxgi_texture_staging.h" #include #include #include #include #include "modules/desktop_capture/win/desktop_capture_utils.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "system_wrappers/include/metrics.h" using Microsoft::WRL::ComPtr; namespace webrtc { DxgiTextureStaging::DxgiTextureStaging(const D3dDevice& device) : device_(device) {} DxgiTextureStaging::~DxgiTextureStaging() = default; bool DxgiTextureStaging::InitializeStage(ID3D11Texture2D* texture) { RTC_DCHECK(texture); D3D11_TEXTURE2D_DESC desc = {0}; texture->GetDesc(&desc); desc.ArraySize = 1; desc.BindFlags = 0; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.MipLevels = 1; desc.MiscFlags = 0; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_STAGING; if (stage_) { AssertStageAndSurfaceAreSameObject(); D3D11_TEXTURE2D_DESC current_desc; stage_->GetDesc(¤t_desc); const bool recreate_needed = (memcmp(&desc, ¤t_desc, sizeof(D3D11_TEXTURE2D_DESC)) != 0); RTC_HISTOGRAM_BOOLEAN("WebRTC.DesktopCapture.StagingTextureRecreate", recreate_needed); if (!recreate_needed) { return true; } // The descriptions are not consistent, we need to create a new // ID3D11Texture2D instance. stage_.Reset(); surface_.Reset(); } else { RTC_DCHECK(!surface_); } _com_error error = device_.d3d_device()->CreateTexture2D( &desc, nullptr, stage_.GetAddressOf()); if (error.Error() != S_OK || !stage_) { RTC_LOG(LS_ERROR) << "Failed to create a new ID3D11Texture2D as stage: " << desktop_capture::utils::ComErrorToString(error); return false; } error = stage_.As(&surface_); if (error.Error() != S_OK || !surface_) { RTC_LOG(LS_ERROR) << "Failed to convert ID3D11Texture2D to IDXGISurface: " << desktop_capture::utils::ComErrorToString(error); return false; } return true; } void DxgiTextureStaging::AssertStageAndSurfaceAreSameObject() { ComPtr left; ComPtr right; bool left_result = SUCCEEDED(stage_.As(&left)); bool right_result = SUCCEEDED(surface_.As(&right)); RTC_DCHECK(left_result); RTC_DCHECK(right_result); RTC_DCHECK(left.Get() == right.Get()); } bool DxgiTextureStaging::CopyFromTexture( const DXGI_OUTDUPL_FRAME_INFO& frame_info, ID3D11Texture2D* texture) { RTC_DCHECK_GT(frame_info.AccumulatedFrames, 0); RTC_DCHECK(texture); // AcquireNextFrame returns a CPU inaccessible IDXGIResource, so we need to // copy it to a CPU accessible staging ID3D11Texture2D. if (!InitializeStage(texture)) { return false; } device_.context()->CopyResource(static_cast(stage_.Get()), static_cast(texture)); *rect() = {0}; _com_error error = surface_->Map(rect(), DXGI_MAP_READ); if (error.Error() != S_OK) { *rect() = {0}; RTC_LOG(LS_ERROR) << "Failed to map the IDXGISurface to a bitmap: " << desktop_capture::utils::ComErrorToString(error); return false; } return true; } bool DxgiTextureStaging::DoRelease() { _com_error error = surface_->Unmap(); if (error.Error() != S_OK) { stage_.Reset(); surface_.Reset(); } // If using staging mode, we only need to recreate ID3D11Texture2D instance. // This will happen during next CopyFrom call. So this function always returns // true. return true; } } // namespace webrtc