onnxruntime
149 строк · 5.8 Кб
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT License.
3
4#include "lib/Api.Image/pch.h"
5#include "inc/ImageConverter.h"
6#include "inc/ImageConversionHelpers.h"
7#include "inc/D3DDeviceCache.h"
8
9using namespace Microsoft::WRL;
10
11using namespace _winml;
12
13void ImageConverter::SyncD3D11ToD3D12(_In_ D3DDeviceCache& device_cache, _In_ ID3D11Texture2D* pD3D11Texture) {
14assert(pD3D11Texture != nullptr);
15
16ComPtr<ID3D11Device> spTextureDevice;
17pD3D11Texture->GetDevice(&spTextureDevice);
18
19if (spTextureDevice.Get() == device_cache.GetD3D11Device()) {
20// If the texture is on D3DDeviceCache's device, we sync using D3DDeviceCache's fences
21device_cache.GPUSyncD3D11ToD3D12();
22} else {
23// Otherwise, sync using our own cached fences
24ComPtr<ID3D11Fence> spD3D11DeviceFence = FetchOrCreateFenceOnDevice(device_cache, spTextureDevice.Get());
25device_cache.SyncD3D11DeviceToConverter(spD3D11DeviceFence.Get());
26}
27}
28
29void ImageConverter::SyncD3D12ToD3D11(_In_ D3DDeviceCache& device_cache, _In_ ID3D11Texture2D* spTexture) {
30assert(spTexture != nullptr);
31
32ComPtr<ID3D11Device> spTextureDevice;
33spTexture->GetDevice(&spTextureDevice);
34
35if (spTextureDevice.Get() == device_cache.GetD3D11Device()) {
36// If the texture is on D3DDeviceCache's device, we sync using D3DDeviceCache's fences
37device_cache.GPUSyncD3D12ToD3D11();
38} else {
39// Otherwise, sync using our own cached fences
40ComPtr<ID3D11Fence> spD3D11DeviceFence = FetchOrCreateFenceOnDevice(device_cache, spTextureDevice.Get());
41device_cache.SyncConverterToD3D11Device(spD3D11DeviceFence.Get());
42}
43}
44
45ComPtr<ID3D11Fence> ImageConverter::FetchOrCreateFenceOnDevice(
46_In_ D3DDeviceCache& device_cache, _In_ ID3D11Device* pD3D11Device
47) {
48assert(pD3D11Device != nullptr);
49
50ComPtr<ID3D11Fence> fence;
51UINT comPtrSize = static_cast<UINT>(sizeof(fence.GetAddressOf()));
52
53if (FAILED(pD3D11Device->GetPrivateData(device_cache.GetFenceGuid(), &comPtrSize, fence.GetAddressOf())) ||
54fence.Get() == nullptr) {
55// There's no fence on the device, so create a new one
56ComPtr<ID3D11Device5> spD3D11Device5;
57WINML_THROW_IF_FAILED(pD3D11Device->QueryInterface(IID_PPV_ARGS(&spD3D11Device5)));
58WINML_THROW_IF_FAILED(spD3D11Device5->OpenSharedFence(device_cache.GetConverterFenceHandle(), IID_PPV_ARGS(&fence))
59);
60
61// Store the fence on the device
62WINML_THROW_IF_FAILED(spD3D11Device5->SetPrivateDataInterface(device_cache.GetFenceGuid(), fence.Get()));
63}
64
65return fence;
66}
67
68void ImageConverter::ResetCommandList(_In_ D3DDeviceCache& device_cache) {
69if (!command_list_) {
70assert(command_allocator_ == nullptr);
71
72WINML_THROW_IF_FAILED(device_cache.GetD3D12Device()->CreateCommandAllocator(
73device_cache.GetCommandQueue()->GetDesc().Type, IID_PPV_ARGS(command_allocator_.ReleaseAndGetAddressOf())
74));
75
76WINML_THROW_IF_FAILED(device_cache.GetD3D12Device()->CreateCommandList(
770,
78device_cache.GetCommandQueue()->GetDesc().Type,
79command_allocator_.Get(),
80pipeline_state_.Get(),
81IID_PPV_ARGS(command_list_.ReleaseAndGetAddressOf())
82));
83} else {
84command_list_->Reset(command_allocator_.Get(), pipeline_state_.Get());
85}
86}
87
88void ImageConverter::ResetAllocator() {
89WINML_THROW_IF_FAILED(command_allocator_->Reset());
90}
91
92ComPtr<ID3D11Texture2D> ImageConverter::CreateTextureFromUnsupportedColorFormat(
93const wm::IVideoFrame& videoFrame,
94const wgi::BitmapBounds& inputBounds,
95const wgi::BitmapBounds& outputBounds,
96wgdx::DirectXPixelFormat newFormat
97) {
98assert(videoFrame != nullptr);
99
100// Make sure we create the new video frame on the same device. We don't want the VideoFrame pipeline to implicitly share the texture between
101// 2 devices since we will need to do it ourselves anyway.
102auto device = _winmli::GetDeviceFromDirect3DSurface(videoFrame.Direct3DSurface());
103
104auto spNewVideoFrame =
105wm::VideoFrame::CreateAsDirect3D11SurfaceBacked(newFormat, outputBounds.Width, outputBounds.Height, device);
106videoFrame.as<wm::IVideoFrame2>().CopyToAsync(spNewVideoFrame, inputBounds, outputBounds).get();
107
108using namespace Windows::Graphics::DirectX::Direct3D11;
109
110auto spDxgiInterfaceAccess = spNewVideoFrame.Direct3DSurface().as<IDirect3DDxgiInterfaceAccess>();
111ComPtr<ID3D11Texture2D> d3d11Texture;
112WINML_THROW_IF_FAILED(spDxgiInterfaceAccess->GetInterface(IID_PPV_ARGS(&d3d11Texture)));
113
114return d3d11Texture;
115}
116
117void ImageConverter::CopyTextureIntoTexture(
118_In_ ID3D11Texture2D* pTextureFrom, _In_ const wgi::BitmapBounds& inputBounds, _Inout_ ID3D11Texture2D* pTextureTo
119) {
120assert(pTextureFrom != nullptr);
121assert(pTextureTo != nullptr);
122
123D3D11_TEXTURE2D_DESC textureFromDesc, textureToDesc;
124pTextureFrom->GetDesc(&textureFromDesc);
125pTextureTo->GetDesc(&textureToDesc);
126
127assert(inputBounds.Width <= textureFromDesc.Width && inputBounds.Width <= textureToDesc.Width);
128assert(inputBounds.Height <= textureFromDesc.Height && inputBounds.Height <= textureToDesc.Height);
129
130ComPtr<ID3D11Device> spDeviceFrom, spDeviceTo;
131pTextureFrom->GetDevice(&spDeviceFrom);
132pTextureTo->GetDevice(&spDeviceTo);
133
134assert(spDeviceFrom.Get() == spDeviceTo.Get());
135
136ComPtr<ID3D11DeviceContext> spDeviceContext;
137spDeviceFrom->GetImmediateContext(&spDeviceContext);
138
139if (textureFromDesc.Width != textureToDesc.Width || textureFromDesc.Height != textureToDesc.Height) {
140// We can't copy the whole resource, so we have to use the slower CopySubresource() function
141D3D11_BOX cropBox = CD3D11_BOX(
142inputBounds.X, inputBounds.Y, 0, inputBounds.X + inputBounds.Width, inputBounds.Y + inputBounds.Height, 1
143);
144spDeviceContext->CopySubresourceRegion(pTextureTo, 0, 0, 0, 0, pTextureFrom, 0, &cropBox);
145} else {
146// Use the faster CopyResource() function since both textures have the same dimensions
147spDeviceContext->CopyResource(pTextureTo, pTextureFrom);
148}
149}
150