From 4ac46ce82b62f385e40b53d03593e6352c226b2a Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Fri, 26 Apr 2024 00:35:54 +0900 Subject: [PATCH] d3d12screencapturesrc: Performance improvement Process captured frame using d3d11 instead of d3d12, and use shared fence when copying processed d3d11 texture to d3d12 resource. In this way, capture CPU thread does not need to wait for fence signal. Part-of: --- .../sys/d3d12/gstd3d12dxgicapture.cpp | 1421 +++++++---------- .../sys/d3d12/gstd3d12screencapturesrc.cpp | 6 +- 2 files changed, 574 insertions(+), 853 deletions(-) diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12dxgicapture.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12dxgicapture.cpp index 8ca05a5564..353e68c23b 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12dxgicapture.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12dxgicapture.cpp @@ -47,7 +47,7 @@ #include "gstd3d12dxgicapture.h" #include "gstd3d12pluginutils.h" -#include +#include #include #include #include @@ -253,13 +253,6 @@ struct PtrInfo UINT64 token_ = 0; }; -struct MoveRectData -{ - RECT src_rect; - RECT dst_rect; - D3D12_BOX box; -}; - struct VERTEX { XMFLOAT3 Pos; @@ -271,7 +264,7 @@ class DesktopDupCtx public: DesktopDupCtx () {} - GstFlowReturn Init (HMONITOR monitor) + GstFlowReturn Init (HMONITOR monitor, HANDLE fence_handle) { ComPtr adapter; ComPtr output; @@ -301,29 +294,30 @@ public: GST_WARNING ("OpenInputDesktop() failed, error %lu", GetLastError()); } - static const D3D_FEATURE_LEVEL feature_levels[] = { - D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, - }; + D3D_FEATURE_LEVEL feature_level = D3D_FEATURE_LEVEL_11_1; + ComPtr device; + ComPtr context; hr = D3D11CreateDevice (adapter.Get (), D3D_DRIVER_TYPE_UNKNOWN, nullptr, - D3D11_CREATE_DEVICE_BGRA_SUPPORT, feature_levels, - G_N_ELEMENTS (feature_levels), D3D11_SDK_VERSION, &device_, nullptr, - nullptr); - if (FAILED (hr)) { - hr = D3D11CreateDevice (adapter.Get (), D3D_DRIVER_TYPE_UNKNOWN, nullptr, - D3D11_CREATE_DEVICE_BGRA_SUPPORT, &feature_levels[1], - G_N_ELEMENTS (feature_levels) - 1, D3D11_SDK_VERSION, &device_, - nullptr, nullptr); - } - + D3D11_CREATE_DEVICE_BGRA_SUPPORT, &feature_level, 1, D3D11_SDK_VERSION, + &device, nullptr, &context); if (FAILED (hr)) { GST_ERROR ("Couldn't create d3d11 device"); return GST_FLOW_ERROR; } + hr = device.As (&device_); + if (FAILED (hr)) { + GST_ERROR ("ID3D11Device5 interface unavilable"); + return GST_FLOW_ERROR; + } + + hr = context.As (&context_); + if (FAILED (hr)) { + GST_ERROR ("ID3D11DeviceContext4 interface unavilable"); + return GST_FLOW_ERROR; + } + /* FIXME: Use DuplicateOutput1 to avoid potentail color conversion */ hr = output1->DuplicateOutput(device_.Get(), &dupl_); if (FAILED (hr)) { @@ -347,91 +341,494 @@ public: CreateDuplicationExpectedErrors); } + hr = device_->OpenSharedFence (fence_handle, + IID_PPV_ARGS (&shared_fence_)); + if (FAILED (hr)) { + GST_ERROR ("Couldn't create fence"); + return GST_FLOW_ERROR; + } + dupl_->GetDesc (&output_desc_); + D3D11_TEXTURE2D_DESC desc = { }; + desc.Width = output_desc_.ModeDesc.Width; + desc.Height = output_desc_.ModeDesc.Height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_RENDER_TARGET; + + hr = device_->CreateTexture2D (&desc, nullptr, &texture_); + if (FAILED (hr)) { + GST_ERROR ("Couldn't create texture"); + return GST_FLOW_ERROR; + } + + hr = device_->CreateRenderTargetView (texture_.Get (), nullptr, &rtv_); + if (FAILED (hr)) { + GST_ERROR ("Couldn't create render target view"); + return GST_FLOW_ERROR; + } + + viewport_.TopLeftX = 0; + viewport_.TopLeftY = 0; + viewport_.MinDepth = 0; + viewport_.MaxDepth = 1; + viewport_.Width = desc.Width; + viewport_.Height = desc.Height; + + GstD3DShaderByteCode vs_code; + GstD3DShaderByteCode ps_code; + if (!gst_d3d_plugin_shader_get_vs_blob (GST_D3D_PLUGIN_VS_COORD, + GST_D3D_SM_5_0, &vs_code)) { + GST_ERROR ("Couldn't get vs bytecode"); + return GST_FLOW_ERROR; + } + + if (!gst_d3d_plugin_shader_get_ps_blob (GST_D3D_PLUGIN_PS_SAMPLE, + GST_D3D_SM_5_0, &ps_code)) { + GST_ERROR ("Couldn't get ps bytecode"); + return GST_FLOW_ERROR; + } + + D3D11_INPUT_ELEMENT_DESC input_desc[2] = { }; + input_desc[0].SemanticName = "POSITION"; + input_desc[0].SemanticIndex = 0; + input_desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; + input_desc[0].InputSlot = 0; + input_desc[0].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT; + input_desc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + input_desc[0].InstanceDataStepRate = 0; + input_desc[1].SemanticName = "TEXCOORD"; + input_desc[1].SemanticIndex = 0; + input_desc[1].Format = DXGI_FORMAT_R32G32_FLOAT; + input_desc[1].InputSlot = 0; + input_desc[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT; + input_desc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + input_desc[1].InstanceDataStepRate = 0; + + hr = device_->CreateVertexShader (vs_code.byte_code, vs_code.byte_code_len, + nullptr, &vs_); + if (FAILED (hr)) { + GST_ERROR ("Couldn't create vertex shader"); + return GST_FLOW_ERROR; + } + + hr = device_->CreateInputLayout (input_desc, 2, vs_code.byte_code, + vs_code.byte_code_len, &layout_); + if (FAILED (hr)) { + GST_ERROR ("Couldn't create input layout"); + return GST_FLOW_ERROR; + } + + hr = device_->CreatePixelShader (ps_code.byte_code, ps_code.byte_code_len, + nullptr, &ps_); + if (FAILED (hr)) { + GST_ERROR ("Couldn't create pixel shader"); + return GST_FLOW_ERROR; + } + + D3D11_SAMPLER_DESC sampler_desc = { }; + sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sampler_desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + sampler_desc.MaxLOD = D3D11_FLOAT32_MAX; + hr = device_->CreateSamplerState (&sampler_desc, &sampler_); + if (FAILED (hr)) { + GST_ERROR ("Couldn't create sampler state"); + return GST_FLOW_ERROR; + } + return GST_FLOW_OK; } - void ReleaseFrame () + void + setMoveRect (DXGI_OUTDUPL_MOVE_RECT * move_rect, + DXGI_MODE_ROTATION rotation, INT width, INT height, + RECT * src, RECT * dst) { - if (acquired_frame_) { - acquired_frame_ = nullptr; - dupl_->ReleaseFrame (); + switch (rotation) { + case DXGI_MODE_ROTATION_ROTATE90: + src->left = height - (move_rect->SourcePoint.y + + move_rect->DestinationRect.bottom - move_rect->DestinationRect.top); + src->top = move_rect->SourcePoint.x; + src->right = height - move_rect->SourcePoint.y; + src->bottom = move_rect->SourcePoint.x + + move_rect->DestinationRect.right - move_rect->DestinationRect.left; + + dst->left = height - move_rect->DestinationRect.bottom; + dst->top = move_rect->DestinationRect.left; + dst->right = height - move_rect->DestinationRect.top; + dst->bottom = move_rect->DestinationRect.right; + break; + case DXGI_MODE_ROTATION_ROTATE180: + src->left = width - (move_rect->SourcePoint.x + + move_rect->DestinationRect.right - move_rect->DestinationRect.left); + src->top = height - (move_rect->SourcePoint.y + + move_rect->DestinationRect.bottom - move_rect->DestinationRect.top); + src->right = width - move_rect->SourcePoint.x; + src->bottom = height - move_rect->SourcePoint.y; + + dst->left = width - move_rect->DestinationRect.right; + dst->top = height - move_rect->DestinationRect.bottom; + dst->right = width - move_rect->DestinationRect.left; + dst->bottom = height - move_rect->DestinationRect.top; + break; + case DXGI_MODE_ROTATION_ROTATE270: + src->left = move_rect->SourcePoint.x; + src->top = width - (move_rect->SourcePoint.x + + move_rect->DestinationRect.right - move_rect->DestinationRect.left); + src->right = move_rect->SourcePoint.y + + move_rect->DestinationRect.bottom - move_rect->DestinationRect.top; + src->bottom = width - move_rect->SourcePoint.x; + + dst->left = move_rect->DestinationRect.top; + dst->top = width - move_rect->DestinationRect.right; + dst->right = move_rect->DestinationRect.bottom; + dst->bottom = width - move_rect->DestinationRect.left; + break; + case DXGI_MODE_ROTATION_UNSPECIFIED: + case DXGI_MODE_ROTATION_IDENTITY: + default: + src->left = move_rect->SourcePoint.x; + src->top = move_rect->SourcePoint.y; + src->right = move_rect->SourcePoint.x + + move_rect->DestinationRect.right - move_rect->DestinationRect.left; + src->bottom = move_rect->SourcePoint.y + + move_rect->DestinationRect.bottom - move_rect->DestinationRect.top; + + *dst = move_rect->DestinationRect; + break; } } - GstFlowReturn AcquireNextFrame (IDXGIResource ** resource) + GstFlowReturn + copyMoveRects (ID3D11Texture2D * src, DXGI_OUTDUPL_MOVE_RECT * rects, + UINT move_count) { - HRESULT hr; - - move_rect_.clear (); - dirty_rect_.clear (); - dirty_vertex_.clear (); - - if (acquired_frame_) { - acquired_frame_ = nullptr; - dupl_->ReleaseFrame (); + if (!move_texture_) { + D3D11_TEXTURE2D_DESC desc; + src->GetDesc (&desc); + desc.BindFlags = 0; + desc.MiscFlags = 0; + auto hr = device_->CreateTexture2D (&desc, nullptr, &move_texture_); + if (FAILED (hr)) { + GST_ERROR ("Couldn't create move texture"); + return GST_FLOW_ERROR; + } } - hr = dupl_->AcquireNextFrame(0, &frame_info_, &acquired_frame_); - if (hr == DXGI_ERROR_WAIT_TIMEOUT) + for (UINT i = 0; i < move_count; i++) { + RECT src; + RECT dst; + + setMoveRect (&rects[i], output_desc_.Rotation, + output_desc_.ModeDesc.Width, output_desc_.ModeDesc.Height, + &src, &dst); + + D3D11_BOX src_box = { }; + src_box.front = 0; + src_box.back = 1; + src_box.left = src.left; + src_box.top = src.top; + src_box.right = src.right; + src_box.bottom = src.bottom; + + context_->CopySubresourceRegion(move_texture_.Get(), + 0, src.left, src.top, 0, texture_.Get (), 0, &src_box); + context_->CopySubresourceRegion (texture_.Get (), 0, dst.left, dst.top, + 0, move_texture_.Get (), 0, &src_box); + } + + return GST_FLOW_OK; + } + + void + setDirtyVert (RECT * dirty, DXGI_MODE_ROTATION rotation, + INT width, INT height, VERTEX * vert) + { + FLOAT center_x = width / 2.0; + FLOAT center_y = height / 2.0; + + RECT dst = *dirty; + + switch (rotation) { + case DXGI_MODE_ROTATION_ROTATE90: + dst.left = width - dirty->bottom; + dst.top = dirty->left; + dst.right = width - dirty->top; + dst.bottom = dirty->right; + + vert[0].TexCoord = + XMFLOAT2(dirty->right / static_cast(width), + dirty->bottom / static_cast(height)); + vert[1].TexCoord = + XMFLOAT2(dirty->left / static_cast(width), + dirty->bottom / static_cast(height)); + vert[2].TexCoord = + XMFLOAT2(dirty->right / static_cast(width), + dirty->top / static_cast(height)); + vert[5].TexCoord = + XMFLOAT2(dirty->left / static_cast(width), + dirty->top / static_cast(height)); + break; + case DXGI_MODE_ROTATION_ROTATE180: + dst.left = width - dirty->right; + dst.top = height - dirty->bottom; + dst.right = width - dirty->left; + dst.bottom = height - dirty->top; + + vert[0].TexCoord = + XMFLOAT2(dirty->right / static_cast(width), + dirty->top / static_cast(height)); + vert[1].TexCoord = + XMFLOAT2(dirty->right / static_cast(width), + dirty->bottom / static_cast(height)); + vert[2].TexCoord = + XMFLOAT2(dirty->left / static_cast(width), + dirty->top / static_cast(height)); + vert[5].TexCoord = + XMFLOAT2(dirty->left / static_cast(width), + dirty->bottom / static_cast(height)); + break; + case DXGI_MODE_ROTATION_ROTATE270: + dst.left = dirty->top; + dst.top = height - dirty->right; + dst.right = dirty->bottom; + dst.bottom = height - dirty->left; + + vert[0].TexCoord = + XMFLOAT2(dirty->left / static_cast(width), + dirty->top / static_cast(height)); + vert[1].TexCoord = + XMFLOAT2(dirty->right / static_cast(width), + dirty->top / static_cast(height)); + vert[2].TexCoord = + XMFLOAT2(dirty->left / static_cast(width), + dirty->bottom / static_cast(height)); + vert[5].TexCoord = + XMFLOAT2(dirty->right / static_cast(width), + dirty->bottom / static_cast(height)); + break; + case DXGI_MODE_ROTATION_UNSPECIFIED: + case DXGI_MODE_ROTATION_IDENTITY: + default: + vert[0].TexCoord = + XMFLOAT2(dirty->left / static_cast(width), + dirty->bottom / static_cast(height)); + vert[1].TexCoord = + XMFLOAT2(dirty->left / static_cast(width), + dirty->top / static_cast(height)); + vert[2].TexCoord = + XMFLOAT2(dirty->right / static_cast(width), + dirty->bottom / static_cast(height)); + vert[5].TexCoord = + XMFLOAT2(dirty->right / static_cast(width), + dirty->top / static_cast(height)); + break; + } + + vert[0].Pos = + XMFLOAT3( + (dst.left - center_x) / center_x, + -1 * (dst.bottom - center_y) / center_y, + 0.0f); + vert[1].Pos = + XMFLOAT3( + (dst.left - center_x) / center_x, + -1 * (dst.top - center_y) / center_y, + 0.0f); + vert[2].Pos = + XMFLOAT3( + (dst.right - center_x) / center_x, + -1 * (dst.bottom - center_y) / center_y, + 0.0f); + vert[3].Pos = vert[2].Pos; + vert[4].Pos = vert[1].Pos; + vert[5].Pos = + XMFLOAT3( + (dst.right - center_x) / center_x, + -1 * (dst.top - center_y) / center_y, + 0.0f); + + vert[3].TexCoord = vert[2].TexCoord; + vert[4].TexCoord = vert[1].TexCoord; + } + + GstFlowReturn + copyDirtyRects (ID3D11Texture2D * src, RECT * dirty_rects, UINT dirty_count) + { + if (dirty_count == 0) return GST_FLOW_OK; + ComPtr cur_srv; + auto hr = device_->CreateShaderResourceView (src, nullptr, &cur_srv); if (FAILED (hr)) { - GST_WARNING ("AcquireNextFrame failed with 0x%x", (guint) hr); - return flow_return_from_hr (device_.Get (), hr, FrameInfoExpectedErrors); + GST_ERROR ("Couldn't create shader resource view"); + return GST_FLOW_ERROR; } - metadata_buffer_.resize (frame_info_.TotalMetadataBufferSize); - if (frame_info_.TotalMetadataBufferSize > 0) { - UINT buf_size = frame_info_.TotalMetadataBufferSize; - hr = dupl_->GetFrameMoveRects (buf_size, - (DXGI_OUTDUPL_MOVE_RECT *) metadata_buffer_.data (), &buf_size); - if (FAILED (hr)) { - GST_ERROR ("Couldn't get move rect, hr: 0x%x", (guint) hr); - return flow_return_from_hr (device_.Get (), - hr, FrameInfoExpectedErrors); - } + auto byte_needed = sizeof (VERTEX) * 6 * dirty_count; + dirty_vertex_.resize (dirty_count * 6); + VERTEX *vert_data = dirty_vertex_.data (); - auto move_count = buf_size / sizeof (DXGI_OUTDUPL_MOVE_RECT); - buildMoveRects (move_count); - - auto dirty_rects = metadata_buffer_.data () + buf_size; - buf_size = frame_info_.TotalMetadataBufferSize - buf_size; - - hr = dupl_->GetFrameDirtyRects (buf_size, (RECT *) dirty_rects, - &buf_size); - if (FAILED (hr)) { - GST_ERROR ("Couldn't get dirty rect, hr: 0x%x", (guint) hr); - return flow_return_from_hr (device_.Get (), - hr, FrameInfoExpectedErrors); - } - - auto dirty_count = buf_size / sizeof (RECT); - buildDirtyVertex ((RECT *) dirty_rects, dirty_count); + for (guint i = 0; i < dirty_count; i++, vert_data += 6) { + setDirtyVert (&dirty_rects[i], output_desc_.Rotation, + output_desc_.ModeDesc.Width, output_desc_.ModeDesc.Height, + vert_data); } - if (frame_info_.LastMouseUpdateTime.QuadPart != 0) { - ptr_info_.position_info = frame_info_.PointerPosition; - ptr_info_.LastTimeStamp = frame_info_.LastMouseUpdateTime; + if (byte_needed > vertext_buf_size_) + vertex_buf_ = nullptr; - if (frame_info_.PointerShapeBufferSize > 0) { - UINT buf_size; - ptr_info_.shape_buffer.resize (frame_info_.PointerShapeBufferSize); - hr = dupl_->GetFramePointerShape (frame_info_.PointerShapeBufferSize, - (void *) ptr_info_.shape_buffer.data (), &buf_size, - &ptr_info_.shape_info); + if (!vertex_buf_) { + vertext_buf_size_ = byte_needed; + + D3D11_BUFFER_DESC buf_desc = { }; + D3D11_SUBRESOURCE_DATA subresource = { }; + buf_desc.Usage = D3D11_USAGE_DYNAMIC; + buf_desc.ByteWidth = byte_needed; + buf_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + buf_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + subresource.pSysMem = dirty_vertex_.data (); + subresource.SysMemPitch = byte_needed; + + hr = device_->CreateBuffer (&buf_desc, &subresource, &vertex_buf_); + if (FAILED (hr)) { + GST_ERROR ("Couldn't create vertex buffer"); + return GST_FLOW_ERROR; + } + } else { + D3D11_MAPPED_SUBRESOURCE mapped; + hr = context_->Map (vertex_buf_.Get (), 0, D3D11_MAP_WRITE_DISCARD, + 0, &mapped); + if (FAILED (hr)) { + GST_ERROR ("Couldn't map vertex buffer"); + return GST_FLOW_ERROR; + } + + memcpy (mapped.pData, dirty_vertex_.data (), byte_needed); + context_->Unmap (vertex_buf_.Get (), 0); + } + + UINT stride = sizeof (VERTEX); + UINT offset = 0; + ID3D11Buffer *vert[] = { vertex_buf_.Get () }; + context_->IASetVertexBuffers (0, 1, vert, &stride, &offset); + context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + context_->IASetInputLayout(layout_.Get()); + context_->VSSetShader(vs_.Get(), nullptr, 0); + context_->PSSetShader(ps_.Get(), nullptr, 0); + + ID3D11ShaderResourceView *srv[] = { cur_srv.Get () }; + context_->PSSetShaderResources(0, 1, srv); + + ID3D11SamplerState *sampler[] = { sampler_.Get () }; + context_->PSSetSamplers(0, 1, sampler); + + context_->RSSetViewports (1, &viewport_); + + ID3D11RenderTargetView *rtv[] = { rtv_.Get () }; + context_->OMSetRenderTargets(1, rtv, nullptr); + context_->OMSetBlendState(nullptr, nullptr, 0xFFFFFFFF); + + context_->Draw (6 * dirty_count, 0); + + srv[0] = nullptr; + rtv[0] = nullptr; + + context_->PSSetShaderResources(0, 1, srv); + context_->OMSetRenderTargets(1, rtv, nullptr); + + return GST_FLOW_OK; + } + + GstFlowReturn + Execute (ID3D11Texture2D * dest, D3D11_BOX * src_box, UINT64 fence_val) + { + ComPtr resource; + auto hr = dupl_->AcquireNextFrame(0, &frame_info_, &resource); + if (hr != DXGI_ERROR_WAIT_TIMEOUT) { + if (FAILED (hr)) { + GST_WARNING ("AcquireNextFrame failed with 0x%x", (guint) hr); + return flow_return_from_hr (device_.Get (), hr, FrameInfoExpectedErrors); + } + + ComPtr cur_texture; + resource.As (&cur_texture); + if (!cur_texture) { + GST_ERROR ("Couldn't get texture interface"); + return GST_FLOW_ERROR; + } + + metadata_buffer_.resize (frame_info_.TotalMetadataBufferSize); + if (frame_info_.TotalMetadataBufferSize > 0) { + UINT buf_size = frame_info_.TotalMetadataBufferSize; + hr = dupl_->GetFrameMoveRects (buf_size, + (DXGI_OUTDUPL_MOVE_RECT *) metadata_buffer_.data (), &buf_size); if (FAILED (hr)) { - return flow_return_from_hr(device_.Get (), + GST_ERROR ("Couldn't get move rect, hr: 0x%x", (guint) hr); + return flow_return_from_hr (device_.Get (), hr, FrameInfoExpectedErrors); } - ptr_info_.BuildTexture (); + auto move_count = buf_size / sizeof (DXGI_OUTDUPL_MOVE_RECT); + if (move_count > 0) { + auto ret = copyMoveRects (cur_texture.Get (), + (DXGI_OUTDUPL_MOVE_RECT *) metadata_buffer_.data (), move_count); + if (ret != GST_FLOW_OK) + return ret; + } + + auto dirty_rects = metadata_buffer_.data () + buf_size; + buf_size = frame_info_.TotalMetadataBufferSize - buf_size; + + hr = dupl_->GetFrameDirtyRects (buf_size, (RECT *) dirty_rects, + &buf_size); + if (FAILED (hr)) { + GST_ERROR ("Couldn't get dirty rect, hr: 0x%x", (guint) hr); + return flow_return_from_hr (device_.Get (), + hr, FrameInfoExpectedErrors); + } + + auto dirty_count = buf_size / sizeof (RECT); + if (dirty_count > 0) { + auto ret = copyDirtyRects (cur_texture.Get (), (RECT *) dirty_rects, + dirty_count); + if (ret != GST_FLOW_OK) + return ret; + } } + + if (frame_info_.LastMouseUpdateTime.QuadPart != 0) { + ptr_info_.position_info = frame_info_.PointerPosition; + ptr_info_.LastTimeStamp = frame_info_.LastMouseUpdateTime; + + if (frame_info_.PointerShapeBufferSize > 0) { + UINT buf_size; + ptr_info_.shape_buffer.resize (frame_info_.PointerShapeBufferSize); + hr = dupl_->GetFramePointerShape (frame_info_.PointerShapeBufferSize, + (void *) ptr_info_.shape_buffer.data (), &buf_size, + &ptr_info_.shape_info); + if (FAILED (hr)) { + return flow_return_from_hr(device_.Get (), + hr, FrameInfoExpectedErrors); + } + + ptr_info_.BuildTexture (); + } + } + + dupl_->ReleaseFrame (); } - *resource = acquired_frame_.Get (); - (*resource)->AddRef (); + context_->CopySubresourceRegion (dest, 0, 0, 0, 0, + texture_.Get (), 0, src_box); + context_->Signal (shared_fence_.Get(), fence_val); return GST_FLOW_OK; } @@ -447,213 +844,19 @@ public: return output_desc_; } - UINT GetMoveCount () - { - return move_rect_.size (); - } - - const std::vector & GetMoveRects () - { - return move_rect_; - } - - UINT GetDirtyCount () - { - return dirty_rect_.size (); - } - - const std::vector & GetDirtyRects () - { - return dirty_rect_; - } - - const std::vector & GetDirtyVertex () - { - return dirty_vertex_; - } - const PtrInfo & GetPointerInfo () { return ptr_info_; } -private: - void buildMoveRects (UINT move_count) + ID3D11Fence * GetFence () { - INT width = (INT) output_desc_.ModeDesc.Width; - INT height = (INT) output_desc_.ModeDesc.Height; - - for (UINT i = 0; i < move_count; i++) { - DXGI_OUTDUPL_MOVE_RECT *move_rect = - ((DXGI_OUTDUPL_MOVE_RECT *) metadata_buffer_.data ()) + i; - RECT src_rect; - RECT dst_rect; - - switch (output_desc_.Rotation) { - case DXGI_MODE_ROTATION_UNSPECIFIED: - case DXGI_MODE_ROTATION_IDENTITY: - src_rect.left = move_rect->SourcePoint.x; - src_rect.top = move_rect->SourcePoint.y; - src_rect.right = move_rect->SourcePoint.x + - move_rect->DestinationRect.right - move_rect->DestinationRect.left; - src_rect.bottom = move_rect->SourcePoint.y + - move_rect->DestinationRect.bottom - move_rect->DestinationRect.top; - dst_rect = move_rect->DestinationRect; - break; - case DXGI_MODE_ROTATION_ROTATE90: - src_rect.left = height - (move_rect->SourcePoint.y + - move_rect->DestinationRect.bottom - move_rect->DestinationRect.top); - src_rect.top = move_rect->SourcePoint.x; - src_rect.right = height - move_rect->SourcePoint.y; - src_rect.bottom = move_rect->SourcePoint.x + - move_rect->DestinationRect.right - move_rect->DestinationRect.left; - - dst_rect.left = height - move_rect->DestinationRect.bottom; - dst_rect.top = move_rect->DestinationRect.left; - dst_rect.right = height - move_rect->DestinationRect.top; - dst_rect.bottom = move_rect->DestinationRect.right; - break; - case DXGI_MODE_ROTATION_ROTATE180: - src_rect.left = width - (move_rect->SourcePoint.x + - move_rect->DestinationRect.right - move_rect->DestinationRect.left); - src_rect.top = height - (move_rect->SourcePoint.y + - move_rect->DestinationRect.bottom - move_rect->DestinationRect.top); - src_rect.right = width - move_rect->SourcePoint.x; - src_rect.bottom = height - move_rect->SourcePoint.y; - - dst_rect.left = width - move_rect->DestinationRect.right; - dst_rect.top = height - move_rect->DestinationRect.bottom; - dst_rect.right = width - move_rect->DestinationRect.left; - dst_rect.bottom = height - move_rect->DestinationRect.top; - break; - case DXGI_MODE_ROTATION_ROTATE270: - src_rect.left = move_rect->SourcePoint.x; - src_rect.top = width - (move_rect->SourcePoint.x + - move_rect->DestinationRect.right - move_rect->DestinationRect.left); - src_rect.right = move_rect->SourcePoint.y + - move_rect->DestinationRect.bottom - move_rect->DestinationRect.top; - src_rect.bottom = width - move_rect->SourcePoint.x; - - dst_rect.left = move_rect->DestinationRect.top; - dst_rect.top = width - move_rect->DestinationRect.right; - dst_rect.right = move_rect->DestinationRect.bottom; - dst_rect.bottom = width - move_rect->DestinationRect.left; - break; - default: - continue; - } - - MoveRectData rect_data = { }; - rect_data.src_rect = src_rect; - rect_data.dst_rect = dst_rect; - rect_data.box.left = src_rect.left; - rect_data.box.top = src_rect.top; - rect_data.box.right = src_rect.right; - rect_data.box.bottom = src_rect.bottom; - rect_data.box.front = 0; - rect_data.box.back = 1; - - move_rect_.push_back (rect_data); - } + return shared_fence_.Get (); } - void buildDirtyVertex (RECT * rects, UINT num_rect) + ID3D11Device * GetDevice () { - if (num_rect == 0) - return; - - dirty_vertex_.resize (num_rect * 6); - FLOAT width = output_desc_.ModeDesc.Width; - FLOAT height = output_desc_.ModeDesc.Height; - FLOAT center_x = width / 2.0f; - FLOAT center_y = height / 2.0f; - - for (UINT i = 0; i < num_rect; i++) { - RECT dirty = rects[i]; - RECT dest_dirty = dirty; - UINT base = i * 6; - - dirty_rect_.push_back (dirty); - - switch (output_desc_.Rotation) { - case DXGI_MODE_ROTATION_ROTATE90: - dest_dirty.left = width - dirty.bottom; - dest_dirty.top = dirty.left; - dest_dirty.right = width - dirty.top; - dest_dirty.bottom = dirty.right; - - dirty_vertex_[base].TexCoord = XMFLOAT2 ( - dirty.right / width, dirty.bottom / height); - dirty_vertex_[base + 1].TexCoord = XMFLOAT2 ( - dirty.left / width, dirty.bottom / height); - dirty_vertex_[base + 2].TexCoord = XMFLOAT2 ( - dirty.right / width, dirty.top / height); - dirty_vertex_[base + 5].TexCoord = XMFLOAT2( - dirty.left / width, dirty.top / height); - break; - case DXGI_MODE_ROTATION_ROTATE180: - dest_dirty.left = width - dirty.right; - dest_dirty.top = height - dirty.bottom; - dest_dirty.right = width - dirty.left; - dest_dirty.bottom = height - dirty.top; - - dirty_vertex_[base].TexCoord = XMFLOAT2( - dirty.right / width, dirty.top / height); - dirty_vertex_[base + 1].TexCoord = XMFLOAT2 ( - dirty.right / width, dirty.bottom / height); - dirty_vertex_[base + 2].TexCoord = XMFLOAT2 ( - dirty.left / width, dirty.top / height); - dirty_vertex_[base + 5].TexCoord = XMFLOAT2 ( - dirty.left / width, dirty.bottom / height); - break; - case DXGI_MODE_ROTATION_ROTATE270: - dest_dirty.left = dirty.top; - dest_dirty.top = height - dirty.right; - dest_dirty.right = dirty.bottom; - dest_dirty.bottom = height - dirty.left; - - dirty_vertex_[base].TexCoord = XMFLOAT2 ( - dirty.left / width, dirty.top / height); - dirty_vertex_[base + 1].TexCoord = XMFLOAT2 ( - dirty.right / width, dirty.top / height); - dirty_vertex_[base + 2].TexCoord = XMFLOAT2 ( - dirty.left / width, dirty.bottom / height); - dirty_vertex_[base + 5].TexCoord = XMFLOAT2 ( - dirty.right / width, dirty.bottom / height); - break; - case DXGI_MODE_ROTATION_UNSPECIFIED: - case DXGI_MODE_ROTATION_IDENTITY: - default: - dirty_vertex_[base].TexCoord = XMFLOAT2 ( - dirty.left / width, dirty.bottom / height); - dirty_vertex_[base + 1].TexCoord = XMFLOAT2 ( - dirty.left / width, dirty.top / height); - dirty_vertex_[base + 2].TexCoord = XMFLOAT2 ( - dirty.right / width, dirty.bottom / height); - dirty_vertex_[base + 5].TexCoord = XMFLOAT2 ( - dirty.right / width, dirty.top / height); - break; - } - - /* Set positions */ - dirty_vertex_[base].Pos = XMFLOAT3 ( - (dest_dirty.left - center_x) / center_x, - -1 * (dest_dirty.bottom - center_y) / center_y, 0.0f); - dirty_vertex_[base + 1].Pos = XMFLOAT3 ( - (dest_dirty.left - center_x) / center_x, - -1 * (dest_dirty.top - center_y) / center_y, 0.0f); - dirty_vertex_[base + 2].Pos = XMFLOAT3 ( - (dest_dirty.right - center_x) / center_x, - -1 * (dest_dirty.bottom - center_y) / center_y, 0.0f); - dirty_vertex_[base + 3].Pos = dirty_vertex_[base + 2].Pos; - dirty_vertex_[base + 4].Pos = dirty_vertex_[base + 1].Pos; - dirty_vertex_[base + 5].Pos = XMFLOAT3 ( - (dest_dirty.right - center_x) / center_x, - -1 * (dest_dirty.top - center_y) / center_y, 0.0f); - - dirty_vertex_[base + 3].TexCoord = dirty_vertex_[base + 2].TexCoord; - dirty_vertex_[base + 4].TexCoord = dirty_vertex_[base + 1].TexCoord; - } + return device_.Get (); } private: @@ -661,11 +864,20 @@ private: DXGI_OUTDUPL_DESC output_desc_; DXGI_OUTDUPL_FRAME_INFO frame_info_; ComPtr dupl_; - ComPtr device_; - ComPtr acquired_frame_; - std::vector move_rect_; + ComPtr device_; + ComPtr context_; + ComPtr shared_fence_; + ComPtr texture_; + ComPtr move_texture_; + ComPtr rtv_; + ComPtr sampler_; + ComPtr ps_; + ComPtr vs_; + ComPtr layout_; + ComPtr vertex_buf_; + UINT vertext_buf_size_ = 0; + D3D11_VIEWPORT viewport_ = { }; std::vector dirty_vertex_; - std::vector dirty_rect_; /* frame metadata */ std::vector metadata_buffer_; @@ -681,12 +893,10 @@ struct GstD3D12DxgiCapturePrivate ~GstD3D12DxgiCapturePrivate () { - if (device) { - auto fence_to_wait = MAX (fence_val, mouse_fence_val); - gst_d3d12_device_fence_wait (device, D3D12_COMMAND_LIST_TYPE_DIRECT, - fence_to_wait, event_handle); - } + WaitGPU (); CloseHandle (event_handle); + if (shared_fence_handle) + CloseHandle (shared_fence_handle); gst_clear_buffer (&mouse_buf); gst_clear_buffer (&mouse_xor_buf); gst_clear_object (&ca_pool); @@ -696,30 +906,29 @@ struct GstD3D12DxgiCapturePrivate gst_clear_object (&device); } + void WaitGPU () + { + if (shared_fence) { + auto completed = shared_fence->GetCompletedValue (); + if (completed < fence_val) { + auto hr = shared_fence->SetEventOnCompletion (fence_val, event_handle); + if (SUCCEEDED (hr)) + WaitForSingleObject (event_handle, INFINITE); + } + } + } + GstD3D12Device *device = nullptr; std::unique_ptr ctx; ComPtr output; - ComPtr last_resource; - ComPtr shared_resource; - ComPtr move_frame; - ComPtr processed_frame; - ComPtr rs; - ComPtr pso; GstD3D12CommandAllocatorPool *ca_pool = nullptr; GstD3D12FenceDataPool *fence_data_pool; - GstD3D12FenceData *mouse_fence_data = nullptr; ComPtr cl; - ComPtr mouse_cl; - ComPtr srv_heap; - ComPtr rtv_heap; - ComPtr dirty_vertex_buf; - UINT dirty_vertex_size = 0; + ComPtr shared_fence; + HANDLE shared_fence_handle = nullptr; GstBuffer *mouse_buf = nullptr; GstBuffer *mouse_xor_buf = nullptr; - D3D12_VIEWPORT viewport; - D3D12_RECT scissor_rect; - D3D12_RESOURCE_STATES resource_state = D3D12_RESOURCE_STATE_COMMON; GstD3D12Converter *mouse_blend = nullptr; GstD3D12Converter *mouse_xor_blend = nullptr; @@ -732,7 +941,6 @@ struct GstD3D12DxgiCapturePrivate HANDLE event_handle; guint64 fence_val = 0; - guint64 mouse_fence_val = 0; guint64 mouse_token = 0; @@ -801,29 +1009,6 @@ static gboolean gst_d3d12_dxgi_capture_open (GstD3D12DxgiCapture * self, HMONITOR monitor_handle) { - const D3D12_ROOT_SIGNATURE_FLAGS rs_flags = - D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | - D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | - D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | - D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS | - D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS | - D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS; - const D3D12_STATIC_SAMPLER_DESC static_sampler_desc = { - D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT, - D3D12_TEXTURE_ADDRESS_MODE_CLAMP, - D3D12_TEXTURE_ADDRESS_MODE_CLAMP, - D3D12_TEXTURE_ADDRESS_MODE_CLAMP, - 0, - 1, - D3D12_COMPARISON_FUNC_ALWAYS, - D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK, - 0, - D3D12_FLOAT32_MAX, - 0, - 0, - D3D12_SHADER_VISIBILITY_PIXEL - }; - auto priv = self->priv; priv->monitor_handle = monitor_handle; @@ -890,96 +1075,6 @@ gst_d3d12_dxgi_capture_open (GstD3D12DxgiCapture * self, auto device = gst_d3d12_device_get_device_handle (self->device); - CD3DX12_ROOT_PARAMETER param; - D3D12_DESCRIPTOR_RANGE range; - std::vector < D3D12_ROOT_PARAMETER > param_list; - - range = CD3DX12_DESCRIPTOR_RANGE (D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); - param.InitAsDescriptorTable (1, &range, D3D12_SHADER_VISIBILITY_PIXEL); - param_list.push_back (param); - - D3D12_VERSIONED_ROOT_SIGNATURE_DESC rs_desc = { }; - CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC::Init_1_0 (rs_desc, - param_list.size (), param_list.data (), - 1, &static_sampler_desc, rs_flags); - ComPtr < ID3DBlob > rs_blob; - ComPtr < ID3DBlob > error_blob; - hr = D3DX12SerializeVersionedRootSignature (&rs_desc, - D3D_ROOT_SIGNATURE_VERSION_1_1, &rs_blob, &error_blob); - if (!gst_d3d12_result (hr, self->device)) { - const gchar *error_msg = nullptr; - if (error_blob) - error_msg = (const gchar *) error_blob->GetBufferPointer (); - - GST_ERROR_OBJECT (self, "Couldn't serialize root signature, error: %s", - GST_STR_NULL (error_msg)); - return FALSE; - } - - hr = device->CreateRootSignature (0, rs_blob->GetBufferPointer (), - rs_blob->GetBufferSize (), IID_PPV_ARGS (&priv->rs)); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't create root signature"); - return FALSE; - } - - D3D12_INPUT_ELEMENT_DESC input_desc[2]; - input_desc[0].SemanticName = "POSITION"; - input_desc[0].SemanticIndex = 0; - input_desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; - input_desc[0].InputSlot = 0; - input_desc[0].AlignedByteOffset = D3D12_APPEND_ALIGNED_ELEMENT; - input_desc[0].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; - input_desc[0].InstanceDataStepRate = 0; - - input_desc[1].SemanticName = "TEXCOORD"; - input_desc[1].SemanticIndex = 0; - input_desc[1].Format = DXGI_FORMAT_R32G32_FLOAT; - input_desc[1].InputSlot = 0; - input_desc[1].AlignedByteOffset = D3D12_APPEND_ALIGNED_ELEMENT; - input_desc[1].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; - input_desc[1].InstanceDataStepRate = 0; - - GstD3DShaderByteCode vs_code; - GstD3DShaderByteCode ps_code; - if (!gst_d3d_plugin_shader_get_vs_blob (GST_D3D_PLUGIN_VS_COORD, - GST_D3D_SM_5_0, &vs_code)) { - GST_ERROR_OBJECT (self, "Couldn't get vs bytecode"); - return FALSE; - } - - if (!gst_d3d_plugin_shader_get_ps_blob (GST_D3D_PLUGIN_PS_SAMPLE, - GST_D3D_SM_5_0, &ps_code)) { - GST_ERROR_OBJECT (self, "Couldn't get ps bytecode"); - return FALSE; - } - - D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { }; - pso_desc.pRootSignature = priv->rs.Get (); - pso_desc.VS.BytecodeLength = vs_code.byte_code_len; - pso_desc.VS.pShaderBytecode = vs_code.byte_code; - pso_desc.PS.BytecodeLength = ps_code.byte_code_len; - pso_desc.PS.pShaderBytecode = ps_code.byte_code; - pso_desc.BlendState = CD3DX12_BLEND_DESC (D3D12_DEFAULT); - pso_desc.SampleMask = UINT_MAX; - pso_desc.RasterizerState = CD3DX12_RASTERIZER_DESC (D3D12_DEFAULT); - pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; - pso_desc.DepthStencilState.DepthEnable = FALSE; - pso_desc.DepthStencilState.StencilEnable = FALSE; - pso_desc.InputLayout.pInputElementDescs = input_desc; - pso_desc.InputLayout.NumElements = G_N_ELEMENTS (input_desc); - pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - pso_desc.NumRenderTargets = 1; - pso_desc.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM; - pso_desc.SampleDesc.Count = 1; - - hr = device->CreateGraphicsPipelineState (&pso_desc, - IID_PPV_ARGS (&priv->pso)); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't create pso"); - return FALSE; - } - /* size will be updated later */ GstVideoInfo info; gst_video_info_set_format (&info, GST_VIDEO_FORMAT_BGRA, @@ -1006,23 +1101,17 @@ gst_d3d12_dxgi_capture_open (GstD3D12DxgiCapture * self, priv->mouse_xor_blend = gst_d3d12_converter_new (self->device, &info, &info, &blend_desc, nullptr, nullptr); - D3D12_DESCRIPTOR_HEAP_DESC heap_desc = { }; - heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - heap_desc.NumDescriptors = 1; - heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - hr = device->CreateDescriptorHeap (&heap_desc, - IID_PPV_ARGS (&priv->srv_heap)); + hr = device->CreateFence (0, + D3D12_FENCE_FLAG_SHARED, IID_PPV_ARGS (&priv->shared_fence)); if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't create descriptor heap"); + GST_ERROR_OBJECT (self, "Couldn't create shared fence"); return FALSE; } - heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; - heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; - hr = device->CreateDescriptorHeap (&heap_desc, - IID_PPV_ARGS (&priv->rtv_heap)); + hr = device->CreateSharedHandle (priv->shared_fence.Get (), + nullptr, GENERIC_ALL, nullptr, &priv->shared_fence_handle); if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't create descriptor heap"); + GST_ERROR_OBJECT (self, "Couldn't create shared fence handle"); return FALSE; } @@ -1089,7 +1178,7 @@ gst_d3d12_dxgi_capture_prepare_unlocked (GstD3D12DxgiCapture * self) } auto ctx = std::make_unique < DesktopDupCtx > (); - auto ret = ctx->Init (priv->monitor_handle); + auto ret = ctx->Init (priv->monitor_handle, priv->shared_fence_handle); if (ret != GST_FLOW_OK) { GST_WARNING_OBJECT (self, "Couldn't prepare capturing, %sexpected failure", @@ -1099,53 +1188,7 @@ gst_d3d12_dxgi_capture_prepare_unlocked (GstD3D12DxgiCapture * self) } ctx->GetSize (&priv->cached_width, &priv->cached_height); - priv->viewport.TopLeftX = 0; - priv->viewport.TopLeftY = 0; - priv->viewport.Width = priv->cached_width; - priv->viewport.Height = priv->cached_height; - priv->viewport.MinDepth = 0; - priv->viewport.MaxDepth = 1; - - priv->scissor_rect.left = 0; - priv->scissor_rect.top = 0; - priv->scissor_rect.right = priv->cached_width; - priv->scissor_rect.bottom = priv->cached_height; - - ComPtr < ID3D12Resource > processed_frame; - D3D12_CLEAR_VALUE clear_value = { }; - clear_value.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - clear_value.Color[0] = 0.0f; - clear_value.Color[1] = 0.0f; - clear_value.Color[2] = 0.0f; - clear_value.Color[3] = 1.0f; - - D3D12_HEAP_PROPERTIES heap_prop = - CD3DX12_HEAP_PROPERTIES (D3D12_HEAP_TYPE_DEFAULT); - D3D12_RESOURCE_DESC resource_desc = - CD3DX12_RESOURCE_DESC::Tex2D (DXGI_FORMAT_B8G8R8A8_UNORM, - priv->cached_width, priv->cached_height, 1, 1, 1, 0, - D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | - D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS); - - auto device = gst_d3d12_device_get_device_handle (self->device); - auto hr = device->CreateCommittedResource (&heap_prop, D3D12_HEAP_FLAG_NONE, - &resource_desc, D3D12_RESOURCE_STATE_COMMON, &clear_value, - IID_PPV_ARGS (&processed_frame)); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't create texture"); - return GST_FLOW_ERROR; - } - - D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = { }; - rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; - rtv_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - rtv_desc.Texture2D.PlaneSlice = 0; - - device->CreateRenderTargetView (processed_frame.Get (), &rtv_desc, - GetCPUDescriptorHandleForHeapStart (priv->rtv_heap)); - priv->ctx = std::move (ctx); - priv->processed_frame = processed_frame; return GST_FLOW_OK; } @@ -1190,213 +1233,6 @@ gst_d3d12_dxgi_capture_get_size (GstD3D12ScreenCapture * capture, return gst_d3d12_dxgi_capture_get_size_unlocked (self, width, height); } -static gboolean -gst_d3d12_dxgi_capture_copy_move_rects (GstD3D12DxgiCapture * self, - ID3D12GraphicsCommandList * cl) -{ - auto priv = self->priv; - HRESULT hr; - - auto device = gst_d3d12_device_get_device_handle (self->device); - - GST_LOG_OBJECT (self, "Rendering move rects"); - - std::vector < D3D12_RESOURCE_BARRIER > barriers; - if (!priv->move_frame) { - D3D12_HEAP_PROPERTIES heap_prop = - CD3DX12_HEAP_PROPERTIES (D3D12_HEAP_TYPE_DEFAULT); - D3D12_RESOURCE_DESC resource_desc = GetDesc (priv->processed_frame); - resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE; - hr = device->CreateCommittedResource (&heap_prop, - D3D12_HEAP_FLAG_NONE, &resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, IID_PPV_ARGS (&priv->move_frame)); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't create move texture"); - return FALSE; - } - } - - D3D12_TEXTURE_COPY_LOCATION move_frame = - CD3DX12_TEXTURE_COPY_LOCATION (priv->move_frame.Get ()); - D3D12_TEXTURE_COPY_LOCATION processed_frame = - CD3DX12_TEXTURE_COPY_LOCATION (priv->processed_frame.Get ()); - - const auto & data = priv->ctx->GetMoveRects (); - for (size_t i = 0; i < data.size (); i++) { - const auto & rect = data[i]; - cl->CopyTextureRegion (&move_frame, rect.src_rect.left, rect.src_rect.top, - 0, &processed_frame, &rect.box); - } - - priv->resource_state = D3D12_RESOURCE_STATE_COPY_DEST; - - barriers.clear (); - barriers. - push_back (CD3DX12_RESOURCE_BARRIER::Transition (priv->processed_frame. - Get (), D3D12_RESOURCE_STATE_COPY_SOURCE, - D3D12_RESOURCE_STATE_COPY_DEST)); - barriers.push_back (CD3DX12_RESOURCE_BARRIER::Transition (priv-> - move_frame.Get (), D3D12_RESOURCE_STATE_COPY_DEST, - D3D12_RESOURCE_STATE_COPY_SOURCE)); - cl->ResourceBarrier (barriers.size (), barriers.data ()); - for (size_t i = 0; i < data.size (); i++) { - const auto & rect = data[i]; - cl->CopyTextureRegion (&processed_frame, rect.dst_rect.left, - rect.dst_rect.top, 0, &move_frame, &rect.box); - } - - barriers.clear (); - barriers.push_back (CD3DX12_RESOURCE_BARRIER::Transition (priv-> - move_frame.Get (), D3D12_RESOURCE_STATE_COPY_SOURCE, - D3D12_RESOURCE_STATE_COPY_DEST)); - cl->ResourceBarrier (barriers.size (), barriers.data ()); - - return TRUE; -} - -static gboolean -gst_d3d12_dxgi_capture_copy_dirty_rects (GstD3D12DxgiCapture * self, - IDXGIResource * resource, ID3D12GraphicsCommandList * cl) -{ - auto priv = self->priv; - HRESULT hr; - - auto device = gst_d3d12_device_get_device_handle (self->device); - - GST_LOG_OBJECT (self, "Rendering dirty rects"); - - if (!priv->shared_resource) { - ComPtr < IDXGIResource1 > resource1; - hr = resource->QueryInterface (IID_PPV_ARGS (&resource1)); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "IDXGIResource1 interface unavailable"); - return FALSE; - } - - HANDLE shared_handle; - hr = resource1->CreateSharedHandle (nullptr, DXGI_SHARED_RESOURCE_READ, - nullptr, &shared_handle); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't create shared handle"); - return FALSE; - } - - hr = device->OpenSharedHandle (shared_handle, - IID_PPV_ARGS (&priv->shared_resource)); - CloseHandle (shared_handle); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't open shared resource"); - return FALSE; - } - - D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = { }; - srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; - srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - srv_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - srv_desc.Texture2D.PlaneSlice = 0; - srv_desc.Texture2D.MipLevels = 1; - - device->CreateShaderResourceView (priv->shared_resource.Get (), &srv_desc, - GetCPUDescriptorHandleForHeapStart (priv->srv_heap)); - } - - auto desc = priv->ctx->GetDesc (); - if (desc.Rotation == DXGI_MODE_ROTATION_UNSPECIFIED || - desc.Rotation == DXGI_MODE_ROTATION_IDENTITY) { - const auto & rects = priv->ctx->GetDirtyRects (); - D3D12_TEXTURE_COPY_LOCATION src = - CD3DX12_TEXTURE_COPY_LOCATION (priv->shared_resource.Get ()); - D3D12_TEXTURE_COPY_LOCATION dst = - CD3DX12_TEXTURE_COPY_LOCATION (priv->processed_frame.Get ()); - D3D12_BOX box; - box.front = 0; - box.back = 1; - - GST_LOG_OBJECT (self, "Perform copy"); - - for (size_t i = 0; i < rects.size (); i++) { - const auto & rect = rects[i]; - box.left = rect.left; - box.right = rect.right; - box.top = rect.top; - box.bottom = rect.bottom; - - cl->CopyTextureRegion (&dst, box.left, box.top, 0, &src, &box); - } - - if (priv->resource_state == D3D12_RESOURCE_STATE_COMMON) - priv->resource_state = D3D12_RESOURCE_STATE_COPY_DEST; - } else { - GST_LOG_OBJECT (self, "Perform draw"); - - if (priv->resource_state != D3D12_RESOURCE_STATE_COMMON) { - D3D12_RESOURCE_BARRIER barrier = - CD3DX12_RESOURCE_BARRIER::Transition (priv->processed_frame.Get (), - priv->resource_state, D3D12_RESOURCE_STATE_RENDER_TARGET); - priv->cl->ResourceBarrier (1, &barrier); - } - - cl->SetGraphicsRootSignature (priv->rs.Get ()); - cl->IASetPrimitiveTopology (D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - cl->RSSetViewports (1, &priv->viewport); - cl->RSSetScissorRects (1, &priv->scissor_rect); - D3D12_CPU_DESCRIPTOR_HANDLE rtv_heaps[] = { - GetCPUDescriptorHandleForHeapStart (priv->rtv_heap) - }; - - cl->OMSetRenderTargets (1, rtv_heaps, FALSE, nullptr); - - const auto & vertex = priv->ctx->GetDirtyVertex (); - UINT buf_size = vertex.size () * sizeof (VERTEX); - if (priv->dirty_vertex_size < buf_size) - priv->dirty_vertex_buf = nullptr; - - if (!priv->dirty_vertex_buf) { - D3D12_HEAP_PROPERTIES heap_prop = - CD3DX12_HEAP_PROPERTIES (D3D12_HEAP_TYPE_UPLOAD); - D3D12_RESOURCE_DESC buffer_desc = - CD3DX12_RESOURCE_DESC::Buffer (buf_size); - hr = device->CreateCommittedResource (&heap_prop, - D3D12_HEAP_FLAG_CREATE_NOT_ZEROED, &buffer_desc, - D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, - IID_PPV_ARGS (&priv->dirty_vertex_buf)); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't create vertex buffer"); - return FALSE; - } - - priv->dirty_vertex_size = buf_size; - } - - CD3DX12_RANGE range (0, 0); - void *data; - hr = priv->dirty_vertex_buf->Map (0, &range, &data); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't map buffer"); - return FALSE; - } - - memcpy (data, vertex.data (), buf_size); - priv->dirty_vertex_buf->Unmap (0, nullptr); - D3D12_VERTEX_BUFFER_VIEW vbv = { }; - vbv.BufferLocation = priv->dirty_vertex_buf->GetGPUVirtualAddress (); - vbv.SizeInBytes = buf_size; - vbv.StrideInBytes = sizeof (VERTEX); - - ID3D12DescriptorHeap *heaps[] = { priv->srv_heap.Get () }; - cl->SetDescriptorHeaps (1, heaps); - cl->SetGraphicsRootDescriptorTable (0, - GetGPUDescriptorHandleForHeapStart (priv->srv_heap)); - cl->IASetVertexBuffers (0, 1, &vbv); - cl->DrawInstanced (vertex.size (), 1, 0, 0); - - if (priv->resource_state == D3D12_RESOURCE_STATE_COMMON) - priv->resource_state = D3D12_RESOURCE_STATE_RENDER_TARGET; - } - - return TRUE; -} - static gboolean gst_d3d12_dxgi_capture_draw_mouse (GstD3D12DxgiCapture * self, GstBuffer * buffer, const D3D12_BOX * crop_box) @@ -1500,14 +1336,13 @@ gst_d3d12_dxgi_capture_draw_mouse (GstD3D12DxgiCapture * self, } } - gst_d3d12_fence_data_pool_acquire (priv->fence_data_pool, - &priv->mouse_fence_data); - auto fence_data = priv->mouse_fence_data; + GstD3D12FenceData *fence_data = nullptr; + gst_d3d12_fence_data_pool_acquire (priv->fence_data_pool, &fence_data); GstD3D12CommandAllocator *gst_ca = nullptr; - if (!gst_d3d12_command_allocator_pool_acquire (priv->ca_pool, &gst_ca)) { GST_ERROR_OBJECT (self, "Couldn't acquire command allocator"); + gst_d3d12_fence_data_unref (fence_data); return FALSE; } @@ -1517,22 +1352,24 @@ gst_d3d12_dxgi_capture_draw_mouse (GstD3D12DxgiCapture * self, hr = ca->Reset (); if (!gst_d3d12_result (hr, self->device)) { GST_ERROR_OBJECT (self, "Couldn't reset command allocator"); + gst_d3d12_fence_data_unref (fence_data); return FALSE; } - if (!priv->mouse_cl) { + if (!priv->cl) { hr = device->CreateCommandList (0, D3D12_COMMAND_LIST_TYPE_DIRECT, - ca, nullptr, IID_PPV_ARGS (&priv->mouse_cl)); + ca, nullptr, IID_PPV_ARGS (&priv->cl)); } else { - hr = priv->mouse_cl->Reset (ca, nullptr); + hr = priv->cl->Reset (ca, nullptr); } if (!gst_d3d12_result (hr, self->device)) { GST_ERROR_OBJECT (self, "Couldn't reset command list"); + gst_d3d12_fence_data_unref (fence_data); return FALSE; } - auto cl = priv->mouse_cl; + auto cl = priv->cl; gint ptr_x = info.position_info.Position.x - crop_box->left; gint ptr_y = info.position_info.Position.y - crop_box->top; gint ptr_w = info.width_; @@ -1545,6 +1382,7 @@ gst_d3d12_dxgi_capture_draw_mouse (GstD3D12DxgiCapture * self, if (!gst_d3d12_converter_convert_buffer (priv->mouse_blend, priv->mouse_buf, buffer, fence_data, cl.Get ())) { GST_ERROR_OBJECT (self, "Couldn't build mouse blend command"); + gst_d3d12_fence_data_unref (fence_data); return FALSE; } @@ -1556,6 +1394,7 @@ gst_d3d12_dxgi_capture_draw_mouse (GstD3D12DxgiCapture * self, if (!gst_d3d12_converter_convert_buffer (priv->mouse_xor_blend, priv->mouse_xor_buf, buffer, fence_data, cl.Get ())) { GST_ERROR_OBJECT (self, "Couldn't build mouse blend command"); + gst_d3d12_fence_data_unref (fence_data); return FALSE; } } @@ -1563,9 +1402,29 @@ gst_d3d12_dxgi_capture_draw_mouse (GstD3D12DxgiCapture * self, hr = cl->Close (); if (!gst_d3d12_result (hr, self->device)) { GST_ERROR_OBJECT (self, "Couldn't close command list"); + gst_d3d12_fence_data_unref (fence_data); return FALSE; } + auto cq = gst_d3d12_device_get_command_queue (priv->device, + D3D12_COMMAND_LIST_TYPE_DIRECT); + gst_d3d12_command_queue_execute_wait (cq, priv->shared_fence.Get (), + priv->fence_val); + ID3D12CommandList *cmd_list[] = { cl.Get () }; + + guint64 fence_val = 0; + hr = gst_d3d12_command_queue_execute_command_lists (cq, 1, cmd_list, + &fence_val); + if (!gst_d3d12_result (hr, self->device)) { + GST_ERROR_OBJECT (self, "Couldn't execute command list"); + gst_d3d12_fence_data_unref (fence_data); + return FALSE; + } + + gst_d3d12_command_queue_set_notify (cq, fence_val, fence_data, + (GDestroyNotify) gst_d3d12_fence_data_unref); + gst_d3d12_buffer_after_write (buffer, fence_val); + return TRUE; } @@ -1577,14 +1436,6 @@ gst_d3d12_dxgi_capture_do_capture (GstD3D12DxgiCapture * capture, auto priv = self->priv; GstFlowReturn ret = GST_FLOW_OK; guint width, height; - GstD3D12Memory *dmem; - ID3D12Resource *out_resource; - D3D12_TEXTURE_COPY_LOCATION src, dst; - ID3D12CommandList *cmd_list[1]; - GstD3D12FenceData *fence_data = nullptr; - GstD3D12CommandAllocator *gst_ca = nullptr; - ID3D12CommandAllocator *ca = nullptr; - HRESULT hr; std::lock_guard < std::mutex > lk (priv->lock); if (!priv->ctx) { @@ -1606,12 +1457,20 @@ gst_d3d12_dxgi_capture_do_capture (GstD3D12DxgiCapture * capture, return GST_D3D12_SCREEN_CAPTURE_FLOW_SIZE_CHANGED; } - ComPtr < IDXGIResource > resource; - ret = priv->ctx->AcquireNextFrame (&resource); + auto dmem = (GstD3D12Memory *) gst_buffer_peek_memory (buffer, 0); + auto texture = gst_d3d12_memory_get_d3d11_texture (dmem, + priv->ctx->GetDevice ()); + if (!texture) { + GST_ERROR_OBJECT (self, "Couldn't get d3d11 texture"); + return GST_FLOW_ERROR; + } + + priv->fence_val++; + ret = priv->ctx->Execute (texture, (D3D11_BOX *) crop_box, priv->fence_val); if (ret != GST_FLOW_OK) { + priv->WaitGPU (); + priv->ctx = nullptr; - priv->processed_frame = nullptr; - priv->move_frame = nullptr; if (ret == GST_D3D12_SCREEN_CAPTURE_FLOW_EXPECTED_ERROR) { GST_WARNING_OBJECT (self, "Couldn't capture frame, but expected failure"); } else { @@ -1621,155 +1480,15 @@ gst_d3d12_dxgi_capture_do_capture (GstD3D12DxgiCapture * capture, return ret; } - if (resource) { - if (resource != priv->last_resource) - priv->shared_resource = nullptr; - - priv->last_resource = resource; + if (draw_mouse && !gst_d3d12_dxgi_capture_draw_mouse (self, buffer, crop_box)) { + priv->WaitGPU (); + return GST_FLOW_ERROR; } - GST_LOG_OBJECT (self, "Capture done"); - - bool have_move_rect = false; - if (priv->ctx->GetMoveCount () > 0) - have_move_rect = true; - bool have_dirty_rect = false; - if ((priv->ctx->GetDirtyCount () > 0) && resource) - have_dirty_rect = true; - - std::future < gboolean > mouse_blend_ret; - if (draw_mouse) { - /* Build mouse draw command from other thread */ - mouse_blend_ret = std::async (std::launch::async, - gst_d3d12_dxgi_capture_draw_mouse, self, buffer, crop_box); - } - - auto device = gst_d3d12_device_get_device_handle (self->device); - if (!gst_d3d12_command_allocator_pool_acquire (priv->ca_pool, &gst_ca)) { - GST_ERROR_OBJECT (self, "Couldn't acquire command allocator"); - goto error; - } - - gst_d3d12_fence_data_pool_acquire (priv->fence_data_pool, &fence_data); - gst_d3d12_fence_data_add_notify_mini_object (fence_data, gst_ca); - - ca = gst_d3d12_command_allocator_get_handle (gst_ca); - - hr = ca->Reset (); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't reset command allocator"); - goto error; - } - - if (!priv->cl) { - hr = device->CreateCommandList (0, D3D12_COMMAND_LIST_TYPE_DIRECT, - ca, priv->pso.Get (), IID_PPV_ARGS (&priv->cl)); - } else { - hr = priv->cl->Reset (ca, priv->pso.Get ()); - } - - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't reset command list"); - goto error; - } - - priv->resource_state = D3D12_RESOURCE_STATE_COMMON; - if (have_move_rect && - !gst_d3d12_dxgi_capture_copy_move_rects (self, priv->cl.Get ())) { - GST_ERROR_OBJECT (self, "Couldn't copy move rects"); - goto error; - } - - if (have_dirty_rect && - !gst_d3d12_dxgi_capture_copy_dirty_rects (self, resource.Get (), - priv->cl.Get ())) { - GST_ERROR_OBJECT (self, "Couldn't copy dirty rects"); - goto error; - } - - dmem = (GstD3D12Memory *) gst_buffer_peek_memory (buffer, 0); - out_resource = gst_d3d12_memory_get_resource_handle (dmem); - - src = CD3DX12_TEXTURE_COPY_LOCATION (priv->processed_frame.Get ()); - dst = CD3DX12_TEXTURE_COPY_LOCATION (out_resource); - - if (priv->resource_state != D3D12_RESOURCE_STATE_COMMON) { - D3D12_RESOURCE_BARRIER barrier = - CD3DX12_RESOURCE_BARRIER::Transition (priv->processed_frame.Get (), - priv->resource_state, D3D12_RESOURCE_STATE_COPY_SOURCE); - priv->cl->ResourceBarrier (1, &barrier); - } - - priv->cl->CopyTextureRegion (&dst, 0, 0, 0, &src, crop_box); - - hr = priv->cl->Close (); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't close command list"); - goto error; - } - - cmd_list[0] = priv->cl.Get (); - - if (!gst_d3d12_device_execute_command_lists (self->device, - D3D12_COMMAND_LIST_TYPE_DIRECT, 1, cmd_list, &priv->fence_val)) { - GST_ERROR_OBJECT (self, "Couldn't execute command list"); - goto error; - } - - gst_d3d12_device_set_fence_notify (self->device, - D3D12_COMMAND_LIST_TYPE_DIRECT, priv->fence_val, fence_data); - - gst_d3d12_buffer_after_write (buffer, priv->fence_val); - - if (draw_mouse) { - auto blend_ret = mouse_blend_ret.get (); - if (!blend_ret) { - GST_ERROR_OBJECT (self, "Couldn't build mouse draw command"); - goto error; - } - - if (priv->mouse_fence_data && priv->mouse_cl) { - cmd_list[0] = priv->mouse_cl.Get (); - - if (!gst_d3d12_device_execute_command_lists (self->device, - D3D12_COMMAND_LIST_TYPE_DIRECT, 1, cmd_list, - &priv->mouse_fence_val)) { - GST_ERROR_OBJECT (self, "Couldn't execute command list"); - goto error; - } - - gst_d3d12_device_set_fence_notify (self->device, - D3D12_COMMAND_LIST_TYPE_DIRECT, priv->mouse_fence_val, - priv->mouse_fence_data); - priv->mouse_fence_data = nullptr; - - gst_d3d12_buffer_after_write (buffer, priv->mouse_fence_val); - } - } - - if (have_dirty_rect) { - gst_d3d12_device_fence_wait (self->device, D3D12_COMMAND_LIST_TYPE_DIRECT, - priv->fence_val, priv->event_handle); - } - - priv->ctx->ReleaseFrame (); + /* Set external fence after drawing mouse. + * Otherwise converter will wait for fence value */ + gst_d3d12_memory_set_external_fence (dmem, priv->shared_fence.Get (), + priv->fence_val); return GST_FLOW_OK; - -error: - if (mouse_blend_ret.valid ()) - mouse_blend_ret.get (); - - gst_clear_d3d12_fence_data (&priv->mouse_fence_data); - gst_clear_d3d12_fence_data (&fence_data); - gst_clear_buffer (&priv->mouse_buf); - gst_clear_buffer (&priv->mouse_xor_buf); - resource = nullptr; - priv->last_resource = nullptr; - priv->shared_resource = nullptr; - priv->processed_frame = nullptr; - priv->move_frame = nullptr; - priv->ctx = nullptr; - - return GST_FLOW_ERROR; } diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12screencapturesrc.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12screencapturesrc.cpp index 6698ad2375..87eaed377f 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12screencapturesrc.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12screencapturesrc.cpp @@ -777,11 +777,13 @@ gst_d3d12_screen_capture_src_decide_allocation (GstBaseSrc * bsrc, if (!params) { params = gst_d3d12_allocation_params_new (self->device, &vinfo, GST_D3D12_ALLOCATION_FLAG_DEFAULT, resource_flags, - D3D12_HEAP_FLAG_NONE); + D3D12_HEAP_FLAG_SHARED); } else { gst_d3d12_allocation_params_set_resource_flags (params, resource_flags); gst_d3d12_allocation_params_unset_resource_flags (params, D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE); + gst_d3d12_allocation_params_set_heap_flags (params, + D3D12_HEAP_FLAG_SHARED); } gst_buffer_pool_config_set_d3d12_allocation_params (config, params); @@ -815,7 +817,7 @@ gst_d3d12_screen_capture_src_decide_allocation (GstBaseSrc * bsrc, auto params = gst_d3d12_allocation_params_new (self->device, &vinfo, GST_D3D12_ALLOCATION_FLAG_DEFAULT, resource_flags, - D3D12_HEAP_FLAG_NONE); + D3D12_HEAP_FLAG_SHARED); gst_buffer_pool_config_set_d3d12_allocation_params (config, params); gst_d3d12_allocation_params_free (params);