| Index: webrtc/modules/desktop_capture/win/dxgi_texture_staging.cc
|
| diff --git a/webrtc/modules/desktop_capture/win/dxgi_texture_staging.cc b/webrtc/modules/desktop_capture/win/dxgi_texture_staging.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..403535dd1e613a779e90b38176f93feb6abe7909
|
| --- /dev/null
|
| +++ b/webrtc/modules/desktop_capture/win/dxgi_texture_staging.cc
|
| @@ -0,0 +1,150 @@
|
| +/*
|
| + * 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 "webrtc/modules/desktop_capture/win/dxgi_texture_staging.h"
|
| +
|
| +#include <comdef.h>
|
| +#include <unknwn.h>
|
| +#include <DXGI.h>
|
| +#include <DXGI1_2.h>
|
| +
|
| +#include "webrtc/base/checks.h"
|
| +#include "webrtc/system_wrappers/include/logging.h"
|
| +
|
| +using Microsoft::WRL::ComPtr;
|
| +
|
| +namespace webrtc {
|
| +
|
| +DxgiTextureStaging::DxgiTextureStaging(const DesktopRect& desktop_rect,
|
| + const D3dDevice& device)
|
| + : DxgiTexture(desktop_rect),
|
| + device_(device) {}
|
| +
|
| +bool DxgiTextureStaging::InitializeStage(ID3D11Texture2D* texture) {
|
| + RTC_DCHECK(texture);
|
| + D3D11_TEXTURE2D_DESC desc = {0};
|
| + texture->GetDesc(&desc);
|
| + if (static_cast<int>(desc.Width) != desktop_rect().width() ||
|
| + static_cast<int>(desc.Height) != desktop_rect().height()) {
|
| + LOG(LS_ERROR) << "Texture size is not consistent with current DxgiTexture.";
|
| + return false;
|
| + }
|
| +
|
| + desc.BindFlags = 0;
|
| + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
| + desc.MiscFlags = 0;
|
| + desc.Usage = D3D11_USAGE_STAGING;
|
| + if (stage_) {
|
| + AssertStageAndSurfaceAreSameObject();
|
| + D3D11_TEXTURE2D_DESC current_desc;
|
| + stage_->GetDesc(¤t_desc);
|
| + if (memcmp(&desc, ¤t_desc, sizeof(D3D11_TEXTURE2D_DESC)) == 0) {
|
| + 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 = _com_error(device_.d3d_device()->CreateTexture2D(
|
| + &desc, nullptr, stage_.GetAddressOf()));
|
| + if (error.Error() != S_OK || !stage_) {
|
| + LOG(LS_ERROR) << "Failed to create a new ID3D11Texture2D as stage, error "
|
| + << error.ErrorMessage() << ", code " << error.Error();
|
| + return false;
|
| + }
|
| +
|
| + error = _com_error(stage_.As(&surface_));
|
| + if (error.Error() != S_OK || !surface_) {
|
| + LOG(LS_ERROR) << "Failed to convert ID3D11Texture2D to IDXGISurface, error "
|
| + << error.ErrorMessage() << ", code " << error.Error();
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void DxgiTextureStaging::AssertStageAndSurfaceAreSameObject() {
|
| + ComPtr<IUnknown> left;
|
| + ComPtr<IUnknown> 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::CopyFrom(const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
| + IDXGIResource* resource,
|
| + const DesktopRegion& region) {
|
| + RTC_DCHECK(resource && frame_info.AccumulatedFrames > 0);
|
| + ComPtr<ID3D11Texture2D> texture;
|
| + _com_error error = resource->QueryInterface(
|
| + __uuidof(ID3D11Texture2D),
|
| + reinterpret_cast<void**>(texture.GetAddressOf()));
|
| + if (error.Error() != S_OK || !texture) {
|
| + LOG(LS_ERROR) << "Failed to convert IDXGIResource to ID3D11Texture2D, "
|
| + "error "
|
| + << error.ErrorMessage() << ", code " << error.Error();
|
| + return false;
|
| + }
|
| +
|
| + // AcquireNextFrame returns a CPU inaccessible IDXGIResource, so we need to
|
| + // copy it to a CPU accessible staging ID3D11Texture2D.
|
| + if (!InitializeStage(texture.Get())) {
|
| + return false;
|
| + }
|
| +
|
| + for (DesktopRegion::Iterator it(region); !it.IsAtEnd(); it.Advance()) {
|
| + DesktopRect rect(it.rect());
|
| + rect.Translate(-desktop_rect().left(), -desktop_rect().top());
|
| + D3D11_BOX box;
|
| + box.left = rect.left();
|
| + box.top = rect.top();
|
| + box.right = rect.right();
|
| + box.bottom = rect.bottom();
|
| + box.front = 0;
|
| + box.back = 1;
|
| + device_.context()->CopySubresourceRegion(
|
| + static_cast<ID3D11Resource*>(stage_.Get()),
|
| + 0, rect.left(), rect.top(), 0,
|
| + static_cast<ID3D11Resource*>(texture.Get()),
|
| + 0, &box);
|
| + }
|
| +
|
| + rect_ = {0};
|
| + error = _com_error(surface_->Map(&rect_, DXGI_MAP_READ));
|
| + if (error.Error() != S_OK) {
|
| + rect_ = {0};
|
| + LOG(LS_ERROR) << "Failed to map the IDXGISurface to a bitmap, error "
|
| + << error.ErrorMessage() << ", code " << error.Error();
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool DxgiTextureStaging::DoRelease() {
|
| + _com_error error = _com_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
|
|
|