OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ |
| 10 |
| 11 #include "webrtc/modules/desktop_capture/win/dxgi_texture_staging.h" |
| 12 |
| 13 #include <comdef.h> |
| 14 #include <unknwn.h> |
| 15 #include <DXGI.h> |
| 16 #include <DXGI1_2.h> |
| 17 |
| 18 #include "webrtc/base/checks.h" |
| 19 #include "webrtc/system_wrappers/include/logging.h" |
| 20 |
| 21 using Microsoft::WRL::ComPtr; |
| 22 |
| 23 namespace webrtc { |
| 24 |
| 25 DxgiTextureStaging::DxgiTextureStaging(const DesktopRect& desktop_rect, |
| 26 const D3dDevice& device) |
| 27 : DxgiTexture(desktop_rect), device_(device) {} |
| 28 |
| 29 DxgiTextureStaging::~DxgiTextureStaging() = default; |
| 30 |
| 31 bool DxgiTextureStaging::InitializeStage(ID3D11Texture2D* texture) { |
| 32 RTC_DCHECK(texture); |
| 33 D3D11_TEXTURE2D_DESC desc = {0}; |
| 34 texture->GetDesc(&desc); |
| 35 if (static_cast<int>(desc.Width) != desktop_rect().width() || |
| 36 static_cast<int>(desc.Height) != desktop_rect().height()) { |
| 37 LOG(LS_ERROR) << "Texture size is not consistent with current DxgiTexture."; |
| 38 return false; |
| 39 } |
| 40 |
| 41 desc.BindFlags = 0; |
| 42 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; |
| 43 desc.MiscFlags = 0; |
| 44 desc.Usage = D3D11_USAGE_STAGING; |
| 45 if (stage_) { |
| 46 AssertStageAndSurfaceAreSameObject(); |
| 47 D3D11_TEXTURE2D_DESC current_desc; |
| 48 stage_->GetDesc(¤t_desc); |
| 49 if (memcmp(&desc, ¤t_desc, sizeof(D3D11_TEXTURE2D_DESC)) == 0) { |
| 50 return true; |
| 51 } |
| 52 |
| 53 // The descriptions are not consistent, we need to create a new |
| 54 // ID3D11Texture2D instance. |
| 55 stage_.Reset(); |
| 56 surface_.Reset(); |
| 57 } else { |
| 58 RTC_DCHECK(!surface_); |
| 59 } |
| 60 |
| 61 _com_error error = _com_error(device_.d3d_device()->CreateTexture2D( |
| 62 &desc, nullptr, stage_.GetAddressOf())); |
| 63 if (error.Error() != S_OK || !stage_) { |
| 64 LOG(LS_ERROR) << "Failed to create a new ID3D11Texture2D as stage, error " |
| 65 << error.ErrorMessage() << ", code " << error.Error(); |
| 66 return false; |
| 67 } |
| 68 |
| 69 error = _com_error(stage_.As(&surface_)); |
| 70 if (error.Error() != S_OK || !surface_) { |
| 71 LOG(LS_ERROR) << "Failed to convert ID3D11Texture2D to IDXGISurface, error " |
| 72 << error.ErrorMessage() << ", code " << error.Error(); |
| 73 return false; |
| 74 } |
| 75 |
| 76 return true; |
| 77 } |
| 78 |
| 79 void DxgiTextureStaging::AssertStageAndSurfaceAreSameObject() { |
| 80 ComPtr<IUnknown> left; |
| 81 ComPtr<IUnknown> right; |
| 82 bool left_result = SUCCEEDED(stage_.As(&left)); |
| 83 bool right_result = SUCCEEDED(surface_.As(&right)); |
| 84 RTC_DCHECK(left_result); |
| 85 RTC_DCHECK(right_result); |
| 86 RTC_DCHECK(left.Get() == right.Get()); |
| 87 } |
| 88 |
| 89 bool DxgiTextureStaging::CopyFrom(const DXGI_OUTDUPL_FRAME_INFO& frame_info, |
| 90 IDXGIResource* resource, |
| 91 const DesktopRegion& region) { |
| 92 RTC_DCHECK(resource && frame_info.AccumulatedFrames > 0); |
| 93 ComPtr<ID3D11Texture2D> texture; |
| 94 _com_error error = resource->QueryInterface( |
| 95 __uuidof(ID3D11Texture2D), |
| 96 reinterpret_cast<void**>(texture.GetAddressOf())); |
| 97 if (error.Error() != S_OK || !texture) { |
| 98 LOG(LS_ERROR) << "Failed to convert IDXGIResource to ID3D11Texture2D, " |
| 99 "error " |
| 100 << error.ErrorMessage() << ", code " << error.Error(); |
| 101 return false; |
| 102 } |
| 103 |
| 104 // AcquireNextFrame returns a CPU inaccessible IDXGIResource, so we need to |
| 105 // copy it to a CPU accessible staging ID3D11Texture2D. |
| 106 if (!InitializeStage(texture.Get())) { |
| 107 return false; |
| 108 } |
| 109 |
| 110 for (DesktopRegion::Iterator it(region); !it.IsAtEnd(); it.Advance()) { |
| 111 DesktopRect rect(it.rect()); |
| 112 rect.Translate(-desktop_rect().left(), -desktop_rect().top()); |
| 113 D3D11_BOX box; |
| 114 box.left = rect.left(); |
| 115 box.top = rect.top(); |
| 116 box.right = rect.right(); |
| 117 box.bottom = rect.bottom(); |
| 118 box.front = 0; |
| 119 box.back = 1; |
| 120 device_.context()->CopySubresourceRegion( |
| 121 static_cast<ID3D11Resource*>(stage_.Get()), 0, rect.left(), rect.top(), |
| 122 0, static_cast<ID3D11Resource*>(texture.Get()), 0, &box); |
| 123 } |
| 124 |
| 125 rect_ = {0}; |
| 126 error = _com_error(surface_->Map(&rect_, DXGI_MAP_READ)); |
| 127 if (error.Error() != S_OK) { |
| 128 rect_ = {0}; |
| 129 LOG(LS_ERROR) << "Failed to map the IDXGISurface to a bitmap, error " |
| 130 << error.ErrorMessage() << ", code " << error.Error(); |
| 131 return false; |
| 132 } |
| 133 |
| 134 return true; |
| 135 } |
| 136 |
| 137 bool DxgiTextureStaging::DoRelease() { |
| 138 _com_error error = _com_error(surface_->Unmap()); |
| 139 if (error.Error() != S_OK) { |
| 140 stage_.Reset(); |
| 141 surface_.Reset(); |
| 142 } |
| 143 // If using staging mode, we only need to recreate ID3D11Texture2D instance. |
| 144 // This will happen during next CopyFrom call. So this function always returns |
| 145 // true. |
| 146 return true; |
| 147 } |
| 148 |
| 149 } // namespace webrtc |
OLD | NEW |