4#include <Gfx/Graph/decoders/ColorSpace.hpp>
5#include <Gfx/Graph/decoders/GPUVideoDecoder.hpp>
6#include <Gfx/Graph/decoders/NV12.hpp>
7#include <Gfx/Graph/decoders/P010.hpp>
8#include <Video/GpuFormats.hpp>
10#include <QtGui/private/qrhid3d12_p.h>
13#include <libavformat/avformat.h>
14#if __has_include(<libavutil/hwcontext_d3d12va.h>)
15#include <libavutil/hwcontext_d3d12va.h>
16#define SCORE_HAS_D3D12_HWCONTEXT 1
20#if defined(SCORE_HAS_D3D12_HWCONTEXT)
36struct HWD3D12Decoder : GPUVideoDecoder
39 PixelFormatInfo m_fmt;
41 ID3D12Device* m_dev{};
42 ID3D12CommandQueue* m_cmdQueue{};
43 ID3D12CommandAllocator* m_cmdAlloc{};
44 ID3D12GraphicsCommandList* m_cmdList{};
45 ID3D12Fence* m_fence{};
46 HANDLE m_fenceEvent{};
47 UINT64 m_fenceValue{0};
49 ID3D12Resource* m_yTex{};
50 ID3D12Resource* m_uvTex{};
53 static bool isAvailable(QRhi& rhi)
55 return rhi.backend() == QRhi::D3D12;
58 explicit HWD3D12Decoder(
63 auto* nh =
static_cast<const QRhiD3D12NativeHandles*
>(rhi.nativeHandles());
64 m_dev =
static_cast<ID3D12Device*
>(nh->dev);
65 m_cmdQueue =
static_cast<ID3D12CommandQueue*
>(nh->commandQueue);
68 ~HWD3D12Decoder()
override
77 m_cmdAlloc->Release();
81 CloseHandle(m_fenceEvent);
86 const int w = decoder.width, h = decoder.height;
87 DXGI_FORMAT yFmt = m_fmt.is10bit() ? DXGI_FORMAT_R16_UNORM : DXGI_FORMAT_R8_UNORM;
89 = m_fmt.is10bit() ? DXGI_FORMAT_R16G16_UNORM : DXGI_FORMAT_R8G8_UNORM;
91 auto makeTexture = [&](DXGI_FORMAT fmt, UINT tw, UINT th,
92 ID3D12Resource** out) ->
bool {
93 D3D12_HEAP_PROPERTIES heap{};
94 heap.Type = D3D12_HEAP_TYPE_DEFAULT;
96 D3D12_RESOURCE_DESC desc{};
97 desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
100 desc.DepthOrArraySize = 1;
103 desc.SampleDesc.Count = 1;
104 desc.Flags = D3D12_RESOURCE_FLAG_NONE;
106 return SUCCEEDED(m_dev->CreateCommittedResource(
107 &heap, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON,
108 nullptr, IID_PPV_ARGS(out)));
111 if(!makeTexture(yFmt, w, h, &m_yTex))
113 if(!makeTexture(uvFmt, w / 2, h / 2, &m_uvTex))
117 if(FAILED(m_dev->CreateCommandAllocator(
118 D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_cmdAlloc))))
121 if(FAILED(m_dev->CreateCommandList(
122 0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_cmdAlloc,
nullptr,
123 IID_PPV_ARGS(&m_cmdList))))
130 if(FAILED(m_dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))))
133 m_fenceEvent = CreateEventW(
nullptr, FALSE, FALSE,
nullptr);
141 std::pair<QShader, QShader> init(RenderList& r)
override
143 auto& rhi = *r.state.rhi;
144 const int w = decoder.width, h = decoder.height;
145 auto texFmt = m_fmt.is10bit() ? QRhiTexture::R16 : QRhiTexture::R8;
146 auto uvTexFmt = m_fmt.is10bit() ? QRhiTexture::RG16 : QRhiTexture::RG8;
149 auto tex = rhi.newTexture(texFmt, {w, h}, 1, QRhiTexture::Flag{});
151 auto sampler = rhi.newSampler(
152 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
153 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
155 samplers.push_back({sampler, tex});
158 auto tex = rhi.newTexture(uvTexFmt, {w / 2, h / 2}, 1, QRhiTexture::Flag{});
160 auto sampler = rhi.newSampler(
161 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
162 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
164 samplers.push_back({sampler, tex});
171 r.state, vertexShader(),
172 QString(P010Decoder::frag).arg(
"").arg(colorMatrix(decoder)));
174 QString frag = NV12Decoder::nv12_filter_prologue;
175 frag +=
" vec3 yuv = vec3(y, u, v);\n";
176 frag += NV12Decoder::nv12_filter_epilogue;
178 r.state, vertexShader(), frag.arg(
"").arg(colorMatrix(decoder)));
181 void exec(RenderList& r, QRhiResourceUpdateBatch& res, AVFrame& frame)
override
183 if(!m_ready || !Video::formatIsHardwareDecoded(
184 static_cast<AVPixelFormat
>(frame.format)))
188 auto* d3d12Frame =
reinterpret_cast<AVD3D12VAFrame*
>(frame.data[0]);
189 if(!d3d12Frame || !d3d12Frame->texture)
192 ID3D12Resource* srcTex = d3d12Frame->texture;
193 const int w = decoder.width, h = decoder.height;
196 auto& sync = d3d12Frame->sync_ctx;
197 if(sync.fence && sync.fence_value > 0)
199 if(sync.fence->GetCompletedValue() < sync.fence_value)
201 sync.fence->SetEventOnCompletion(sync.fence_value, m_fenceEvent);
202 WaitForSingleObject(m_fenceEvent, INFINITE);
208 m_cmdList->Reset(m_cmdAlloc,
nullptr);
211 D3D12_RESOURCE_BARRIER barriers[2]{};
212 barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
213 barriers[0].Transition.pResource = m_yTex;
214 barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON;
215 barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
216 barriers[0].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
218 barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
219 barriers[1].Transition.pResource = m_uvTex;
220 barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON;
221 barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
222 barriers[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
224 m_cmdList->ResourceBarrier(2, barriers);
228 D3D12_TEXTURE_COPY_LOCATION dst{};
229 dst.pResource = m_yTex;
230 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
231 dst.SubresourceIndex = 0;
233 D3D12_TEXTURE_COPY_LOCATION src{};
234 src.pResource = srcTex;
235 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
236 src.SubresourceIndex = 0;
238 D3D12_BOX box = {0, 0, 0, (UINT)w, (UINT)h, 1};
239 m_cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, &box);
244 D3D12_TEXTURE_COPY_LOCATION dst{};
245 dst.pResource = m_uvTex;
246 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
247 dst.SubresourceIndex = 0;
249 D3D12_TEXTURE_COPY_LOCATION src{};
250 src.pResource = srcTex;
251 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
252 src.SubresourceIndex = 1;
254 D3D12_BOX box = {0, 0, 0, (UINT)(w / 2), (UINT)(h / 2), 1};
255 m_cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, &box);
259 barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
260 barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON;
261 barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
262 barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON;
264 m_cmdList->ResourceBarrier(2, barriers);
268 ID3D12CommandList* lists[] = {m_cmdList};
269 m_cmdQueue->ExecuteCommandLists(1, lists);
272 m_cmdQueue->Signal(m_fence, m_fenceValue);
273 if(m_fence->GetCompletedValue() < m_fenceValue)
275 m_fence->SetEventOnCompletion(m_fenceValue, m_fenceEvent);
276 WaitForSingleObject(m_fenceEvent, INFINITE);
280 samplers[0].texture->createFrom(
281 QRhiTexture::NativeTexture{quint64(m_yTex), 0});
282 samplers[1].texture->createFrom(
283 QRhiTexture::NativeTexture{quint64(m_uvTex), 0});
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:11
std::pair< QShader, QShader > makeShaders(const RenderState &v, QString vert, QString frag, int multiViewCount)
Get a pair of compiled vertex / fragment shaders from GLSL 4.5 sources.
Definition score-plugin-gfx/Gfx/Graph/Utils.cpp:1238