The open source OpenXR runtime
1// Copyright 2022, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief Misc D3D12 helper routines.
6 * @author Rylie Pavlik <rylie.pavlik@collabora.com>
7 * @ingroup aux_d3d
8 */
9
10#include "d3d_d3d12_helpers.hpp"
11#include "d3d_d3d12_bits.h"
12
13#include "util/u_logging.h"
14
15#include <d3d12.h>
16#include <wil/com.h>
17#include <wil/result.h>
18
19#include <vector>
20#include <stdexcept>
21
22namespace xrt::auxiliary::d3d::d3d12 {
23
24wil::com_ptr<ID3D12Device>
25createDevice(const wil::com_ptr<IDXGIAdapter> &adapter, u_logging_level log_level)
26{
27 if (adapter) {
28 U_LOG_IFL_D(log_level, "Adapter provided.");
29 }
30
31 wil::com_ptr<ID3D12Device> device;
32 THROW_IF_FAILED(
33 D3D12CreateDevice(wil::com_raw_ptr(adapter), D3D_FEATURE_LEVEL_11_1, IID_PPV_ARGS(device.put())));
34
35 return device;
36}
37
38
39HRESULT
40createCommandLists(ID3D12Device &device,
41 ID3D12CommandAllocator &command_allocator,
42 ID3D12Resource &resource,
43 enum xrt_swapchain_usage_bits bits,
44 wil::com_ptr<ID3D12CommandList> out_acquire_command_list,
45 wil::com_ptr<ID3D12CommandList> out_release_command_list)
46{
47
48 //! @todo do we need to set queue access somehow?
49 wil::com_ptr<ID3D12GraphicsCommandList> acquireCommandList;
50 RETURN_IF_FAILED(device.CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, &command_allocator, nullptr,
51 IID_PPV_ARGS(acquireCommandList.put())));
52
53 D3D12_RESOURCE_STATES appResourceState = d3d_convert_usage_bits_to_d3d12_app_resource_state(bits);
54
55 /// @todo No idea if this is right, might depend on whether it's the compute or graphics compositor!
56 D3D12_RESOURCE_STATES compositorResourceState = D3D12_RESOURCE_STATE_GENERIC_READ;
57
58 D3D12_RESOURCE_BARRIER barrier{};
59 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
60 barrier.Transition.pResource = &resource;
61 barrier.Transition.StateBefore = compositorResourceState;
62 barrier.Transition.StateAfter = appResourceState;
63 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
64
65 acquireCommandList->ResourceBarrier(1, &barrier);
66 RETURN_IF_FAILED(acquireCommandList->Close());
67
68 wil::com_ptr<ID3D12GraphicsCommandList> releaseCommandList;
69 RETURN_IF_FAILED(device.CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, &command_allocator, nullptr,
70 IID_PPV_ARGS(releaseCommandList.put())));
71 barrier.Transition.StateBefore = appResourceState;
72 barrier.Transition.StateAfter = compositorResourceState;
73
74 releaseCommandList->ResourceBarrier(1, &barrier);
75 RETURN_IF_FAILED(releaseCommandList->Close());
76
77 out_acquire_command_list = std::move(acquireCommandList);
78 out_release_command_list = std::move(releaseCommandList);
79 return S_OK;
80}
81
82HRESULT
83createCommandListImageCopy(ID3D12Device &device,
84 ID3D12CommandAllocator &command_allocator,
85 ID3D12Resource &resource_src,
86 ID3D12Resource &resource_dst,
87 D3D12_RESOURCE_STATES src_resource_state,
88 D3D12_RESOURCE_STATES dst_resource_state,
89 wil::com_ptr<ID3D12CommandList> &out_copy_command_list)
90{
91 wil::com_ptr<ID3D12GraphicsCommandList> copyCommandList;
92 RETURN_IF_FAILED(device.CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, &command_allocator, nullptr,
93 IID_PPV_ARGS(copyCommandList.put())));
94
95 // Transition images into copy state
96 D3D12_RESOURCE_BARRIER preCopyBarriers[2]{};
97 preCopyBarriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
98 preCopyBarriers[0].Transition.pResource = &resource_src;
99 preCopyBarriers[0].Transition.StateBefore = src_resource_state;
100 preCopyBarriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
101 preCopyBarriers[0].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
102
103 preCopyBarriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
104 preCopyBarriers[1].Transition.pResource = &resource_dst;
105 preCopyBarriers[1].Transition.StateBefore = dst_resource_state;
106 preCopyBarriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
107 preCopyBarriers[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
108
109 copyCommandList->ResourceBarrier(2, preCopyBarriers);
110
111 // Insert texture copy command
112 D3D12_TEXTURE_COPY_LOCATION srcCopyLocation;
113 srcCopyLocation.pResource = &resource_src;
114 srcCopyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
115 srcCopyLocation.SubresourceIndex = 0;
116
117 D3D12_TEXTURE_COPY_LOCATION dstCopyLocation;
118 dstCopyLocation.pResource = &resource_dst;
119 dstCopyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
120 dstCopyLocation.SubresourceIndex = 0;
121
122 copyCommandList->CopyTextureRegion(&dstCopyLocation, 0, 0, 0, &srcCopyLocation, nullptr);
123
124 // Transition images back from copy state
125 D3D12_RESOURCE_BARRIER postCopyBarriers[2]{};
126 postCopyBarriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
127 postCopyBarriers[0].Transition.pResource = &resource_src;
128 postCopyBarriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
129 postCopyBarriers[0].Transition.StateAfter = src_resource_state;
130 postCopyBarriers[0].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
131
132 postCopyBarriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
133 postCopyBarriers[1].Transition.pResource = &resource_dst;
134 postCopyBarriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
135 postCopyBarriers[1].Transition.StateAfter = dst_resource_state;
136 postCopyBarriers[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
137
138 copyCommandList->ResourceBarrier(2, postCopyBarriers);
139
140 RETURN_IF_FAILED(copyCommandList->Close());
141
142 out_copy_command_list = std::move(copyCommandList);
143 return S_OK;
144}
145
146
147wil::com_ptr<ID3D12Resource>
148importImage(ID3D12Device &device, HANDLE h)
149{
150 wil::com_ptr<ID3D12Resource> tex;
151
152 if (h == nullptr) {
153 throw std::logic_error("Cannot import empty handle");
154 }
155 THROW_IF_FAILED(device.OpenSharedHandle(h, IID_PPV_ARGS(tex.put())));
156 return tex;
157}
158
159
160wil::com_ptr<ID3D12Fence1>
161importFence(ID3D12Device &device, HANDLE h)
162{
163 wil::com_ptr<ID3D12Fence1> fence;
164
165 if (h == nullptr) {
166 throw std::logic_error("Cannot import empty handle");
167 }
168 THROW_IF_FAILED(device.OpenSharedHandle(h, IID_PPV_ARGS(fence.put())));
169 return fence;
170}
171
172} // namespace xrt::auxiliary::d3d::d3d12