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)
33struct HWD3D12Decoder : GPUVideoDecoder
36 PixelFormatInfo m_fmt;
38 ID3D12Device* m_dev{};
39 ID3D12CommandQueue* m_cmdQueue{};
40 ID3D12CommandAllocator* m_cmdAlloc{};
41 ID3D12GraphicsCommandList* m_cmdList{};
42 ID3D12Fence* m_fence{};
43 HANDLE m_fenceEvent{};
44 UINT64 m_fenceValue{0};
46 ID3D12Resource* m_yTex{};
47 ID3D12Resource* m_uvTex{};
50 static bool isAvailable(QRhi& rhi)
52 return rhi.backend() == QRhi::D3D12;
55 explicit HWD3D12Decoder(
60 auto* nh =
static_cast<const QRhiD3D12NativeHandles*
>(rhi.nativeHandles());
61 m_dev =
static_cast<ID3D12Device*
>(nh->dev);
62 m_cmdQueue =
static_cast<ID3D12CommandQueue*
>(nh->commandQueue);
65 ~HWD3D12Decoder()
override
74 m_cmdAlloc->Release();
78 CloseHandle(m_fenceEvent);
83 const int w = decoder.width, h = decoder.height;
84 DXGI_FORMAT yFmt = m_fmt.is10bit() ? DXGI_FORMAT_R16_UNORM : DXGI_FORMAT_R8_UNORM;
86 = m_fmt.is10bit() ? DXGI_FORMAT_R16G16_UNORM : DXGI_FORMAT_R8G8_UNORM;
88 auto makeTexture = [&](DXGI_FORMAT fmt, UINT tw, UINT th,
89 ID3D12Resource** out) ->
bool {
90 D3D12_HEAP_PROPERTIES heap{};
91 heap.Type = D3D12_HEAP_TYPE_DEFAULT;
93 D3D12_RESOURCE_DESC desc{};
94 desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
97 desc.DepthOrArraySize = 1;
100 desc.SampleDesc.Count = 1;
101 desc.Flags = D3D12_RESOURCE_FLAG_NONE;
103 return SUCCEEDED(m_dev->CreateCommittedResource(
104 &heap, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON,
105 nullptr, IID_PPV_ARGS(out)));
108 if(!makeTexture(yFmt, w, h, &m_yTex))
110 if(!makeTexture(uvFmt, w / 2, h / 2, &m_uvTex))
114 if(FAILED(m_dev->CreateCommandAllocator(
115 D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_cmdAlloc))))
118 if(FAILED(m_dev->CreateCommandList(
119 0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_cmdAlloc,
nullptr,
120 IID_PPV_ARGS(&m_cmdList))))
127 if(FAILED(m_dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))))
130 m_fenceEvent = CreateEventW(
nullptr, FALSE, FALSE,
nullptr);
138 std::pair<QShader, QShader> init(RenderList& r)
override
140 auto& rhi = *r.state.rhi;
141 const int w = decoder.width, h = decoder.height;
142 auto texFmt = m_fmt.is10bit() ? QRhiTexture::R16 : QRhiTexture::R8;
143 auto uvTexFmt = m_fmt.is10bit() ? QRhiTexture::RG16 : QRhiTexture::RG8;
146 auto tex = rhi.newTexture(texFmt, {w, h}, 1, QRhiTexture::Flag{});
148 auto sampler = rhi.newSampler(
149 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
150 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
152 samplers.push_back({sampler, tex});
155 auto tex = rhi.newTexture(uvTexFmt, {w / 2, h / 2}, 1, QRhiTexture::Flag{});
157 auto sampler = rhi.newSampler(
158 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
159 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
161 samplers.push_back({sampler, tex});
168 r.state, vertexShader(),
169 QString(P010Decoder::frag).arg(
"").arg(colorMatrix(decoder)));
171 QString frag = NV12Decoder::nv12_filter_prologue;
172 frag +=
" vec3 yuv = vec3(y, u, v);\n";
173 frag += NV12Decoder::nv12_filter_epilogue;
175 r.state, vertexShader(), frag.arg(
"").arg(colorMatrix(decoder)));
178 void exec(RenderList& r, QRhiResourceUpdateBatch& res, AVFrame& frame)
override
180 if(!m_ready || !Video::formatIsHardwareDecoded(
181 static_cast<AVPixelFormat
>(frame.format)))
185 auto* d3d12Frame =
reinterpret_cast<AVD3D12VAFrame*
>(frame.data[0]);
186 if(!d3d12Frame || !d3d12Frame->texture)
189 ID3D12Resource* srcTex = d3d12Frame->texture;
190 const int w = decoder.width, h = decoder.height;
193 auto& sync = d3d12Frame->sync_ctx;
194 if(sync.fence && sync.fence_value > 0)
196 if(sync.fence->GetCompletedValue() < sync.fence_value)
198 sync.fence->SetEventOnCompletion(sync.fence_value, m_fenceEvent);
199 WaitForSingleObject(m_fenceEvent, INFINITE);
205 m_cmdList->Reset(m_cmdAlloc,
nullptr);
208 D3D12_RESOURCE_BARRIER barriers[2]{};
209 barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
210 barriers[0].Transition.pResource = m_yTex;
211 barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON;
212 barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
213 barriers[0].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
215 barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
216 barriers[1].Transition.pResource = m_uvTex;
217 barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON;
218 barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
219 barriers[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
221 m_cmdList->ResourceBarrier(2, barriers);
225 D3D12_TEXTURE_COPY_LOCATION dst{};
226 dst.pResource = m_yTex;
227 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
228 dst.SubresourceIndex = 0;
230 D3D12_TEXTURE_COPY_LOCATION src{};
231 src.pResource = srcTex;
232 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
233 src.SubresourceIndex = 0;
235 D3D12_BOX box = {0, 0, 0, (UINT)w, (UINT)h, 1};
236 m_cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, &box);
241 D3D12_TEXTURE_COPY_LOCATION dst{};
242 dst.pResource = m_uvTex;
243 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
244 dst.SubresourceIndex = 0;
246 D3D12_TEXTURE_COPY_LOCATION src{};
247 src.pResource = srcTex;
248 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
249 src.SubresourceIndex = 1;
251 D3D12_BOX box = {0, 0, 0, (UINT)(w / 2), (UINT)(h / 2), 1};
252 m_cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, &box);
256 barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
257 barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON;
258 barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
259 barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON;
261 m_cmdList->ResourceBarrier(2, barriers);
265 ID3D12CommandList* lists[] = {m_cmdList};
266 m_cmdQueue->ExecuteCommandLists(1, lists);
269 m_cmdQueue->Signal(m_fence, m_fenceValue);
270 if(m_fence->GetCompletedValue() < m_fenceValue)
272 m_fence->SetEventOnCompletion(m_fenceValue, m_fenceEvent);
273 WaitForSingleObject(m_fenceEvent, INFINITE);
277 samplers[0].texture->createFrom(
278 QRhiTexture::NativeTexture{quint64(m_yTex), 0});
279 samplers[1].texture->createFrom(
280 QRhiTexture::NativeTexture{quint64(m_uvTex), 0});
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:12
std::pair< QShader, QShader > makeShaders(const RenderState &v, QString vert, QString frag)
Get a pair of compiled vertex / fragment shaders from GLSL 4.5 sources.
Definition score-plugin-gfx/Gfx/Graph/Utils.cpp:395