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..7478728143d0d8f93c274709e5d9207fc67073d4 |
--- /dev/null |
+++ b/webrtc/modules/desktop_capture/win/dxgi_texture_staging.cc |
@@ -0,0 +1,149 @@ |
+/* |
+ * 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) {} |
+ |
+DxgiTextureStaging::~DxgiTextureStaging() = default; |
+ |
+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 |