4#include <Gfx/Graph/decoders/ColorSpace.hpp>
5#include <Gfx/Graph/decoders/DMABufImport.hpp>
6#include <Gfx/Graph/decoders/GPUVideoDecoder.hpp>
7#include <Gfx/Graph/decoders/NV12.hpp>
8#include <Gfx/Graph/decoders/P010.hpp>
9#include <Video/GpuFormats.hpp>
10#include <score/gfx/Vulkan.hpp>
13#include <libavformat/avformat.h>
14#include <libavutil/pixdesc.h>
15#if __has_include(<libavutil/hwcontext.h>)
16#include <libavutil/hwcontext.h>
18#if __has_include(<libavutil/hwcontext_drm.h>)
19#include <libavutil/hwcontext_drm.h>
20#define SCORE_HAS_DRM_HWCONTEXT_VK 1
24#if QT_HAS_VULKAN && defined(SCORE_HAS_DRM_HWCONTEXT_VK) && QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
25#include <QtGui/private/qrhivulkan_p.h>
26#include <qvulkanfunctions.h>
28#include <vulkan/vulkan.h>
33#if defined(VK_EXT_image_drm_format_modifier) && defined(VK_KHR_external_memory_fd)
52struct HWVulkanDecoder : GPUVideoDecoder
55 PixelFormatInfo m_fmt;
56 DMABufPlaneImporter m_importer;
58 using PlaneImport = DMABufPlaneImporter::PlaneImport;
60 static constexpr int NumSlots = 2;
63 PlaneImport planes[2]{};
66 ImportSlot m_slots[NumSlots]{};
69 static bool isAvailable(QRhi& rhi)
71 return DMABufPlaneImporter::isAvailable(rhi);
81 ~HWVulkanDecoder()
override
83 for(
auto& slot : m_slots)
87 void cleanupSlot(ImportSlot& slot)
89 for(
auto& p : slot.planes)
90 m_importer.cleanupPlane(p);
93 av_frame_free(&slot.hwRef);
102 std::pair<QShader, QShader> init(RenderList& r)
override
104 auto& rhi = *r.state.rhi;
105 const auto w = decoder.width, h = decoder.height;
111 auto tex = rhi.newTexture(QRhiTexture::R16, {w, h}, 1, QRhiTexture::Flag{});
113 auto sampler = rhi.newSampler(
114 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
115 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
117 samplers.push_back({sampler, tex});
121 = rhi.newTexture(QRhiTexture::RG16, {w / 2, h / 2}, 1, QRhiTexture::Flag{});
123 auto sampler = rhi.newSampler(
124 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
125 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
127 samplers.push_back({sampler, tex});
130 r.state, vertexShader(),
131 QString(P010Decoder::frag).arg(
"").arg(colorMatrix(decoder)));
137 auto tex = rhi.newTexture(QRhiTexture::R8, {w, h}, 1, QRhiTexture::Flag{});
139 auto sampler = rhi.newSampler(
140 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
141 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
143 samplers.push_back({sampler, tex});
147 = rhi.newTexture(QRhiTexture::RG8, {w / 2, h / 2}, 1, QRhiTexture::Flag{});
149 auto sampler = rhi.newSampler(
150 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
151 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
153 samplers.push_back({sampler, tex});
156 QString frag = NV12Decoder::nv12_filter_prologue;
157 frag +=
" vec3 yuv = vec3(y, u, v);\n";
158 frag += NV12Decoder::nv12_filter_epilogue;
160 r.state, vertexShader(), frag.arg(
"").arg(colorMatrix(decoder)));
168 void exec(RenderList& r, QRhiResourceUpdateBatch& res, AVFrame& frame)
override
170#if LIBAVUTIL_VERSION_MAJOR >= 57
171 if(!Video::formatIsHardwareDecoded(
static_cast<AVPixelFormat
>(frame.format)))
175 auto& slot = m_slots[m_slotIdx];
177 m_slotIdx = (m_slotIdx + 1) % NumSlots;
180 slot.hwRef = av_frame_alloc();
181 if(av_frame_ref(slot.hwRef, &frame) < 0)
183 av_frame_free(&slot.hwRef);
184 slot.hwRef =
nullptr;
189 AVFrame* drmFrame = av_frame_alloc();
190 drmFrame->format = AV_PIX_FMT_DRM_PRIME;
192 int ret = av_hwframe_map(
193 drmFrame, &frame, AV_HWFRAME_MAP_READ | AV_HWFRAME_MAP_DIRECT);
196 qDebug() <<
"HWVulkanDecoder: av_hwframe_map failed:" << ret;
197 av_frame_free(&drmFrame);
201 auto* desc =
reinterpret_cast<AVDRMFrameDescriptor*
>(drmFrame->data[0]);
202 if(!desc || desc->nb_objects < 1)
204 av_frame_unref(drmFrame);
205 av_frame_free(&drmFrame);
221 PlaneInfo planeInfo[2]{};
222 bool planesOk =
false;
223 const int w = decoder.width;
224 const int h = decoder.height;
226 const VkFormat yFmt = m_fmt.is10bit() ? VK_FORMAT_R16_UNORM : VK_FORMAT_R8_UNORM;
227 const VkFormat uvFmt = m_fmt.is10bit() ? VK_FORMAT_R16G16_UNORM : VK_FORMAT_R8G8_UNORM;
229 if(desc->nb_layers >= 2 && desc->layers[0].nb_planes >= 1
230 && desc->layers[1].nb_planes >= 1)
233 auto& yP = desc->layers[0].planes[0];
234 auto& uvP = desc->layers[1].planes[0];
235 planeInfo[0] = {yP.object_index, yP.offset, yP.pitch, yFmt, w, h};
236 planeInfo[1] = {uvP.object_index, uvP.offset, uvP.pitch, uvFmt, w / 2, h / 2};
239 else if(desc->nb_layers >= 1 && desc->layers[0].nb_planes >= 2)
242 auto& yP = desc->layers[0].planes[0];
243 auto& uvP = desc->layers[0].planes[1];
244 planeInfo[0] = {yP.object_index, yP.offset, yP.pitch, yFmt, w, h};
245 planeInfo[1] = {uvP.object_index, uvP.offset, uvP.pitch, uvFmt, w / 2, h / 2};
251 qDebug() <<
"HWVulkanDecoder: unexpected DRM layout, layers:"
253 av_frame_unref(drmFrame);
254 av_frame_free(&drmFrame);
259 for(
int i = 0; i < 2; ++i)
261 auto& pi = planeInfo[i];
262 auto& obj = desc->objects[pi.obj_idx];
263 if(!m_importer.importPlane(
264 slot.planes[i], obj.fd, obj.format_modifier, pi.offset, pi.pitch,
265 pi.format, pi.w, pi.h))
267 qDebug() <<
"HWVulkanDecoder: importPlane failed, plane" << i;
268 av_frame_unref(drmFrame);
269 av_frame_free(&drmFrame);
276 av_frame_unref(drmFrame);
277 av_frame_free(&drmFrame);
280 for(
int i = 0; i < 2; ++i)
282 samplers[i].texture->createFrom(QRhiTexture::NativeTexture{
283 quint64(slot.planes[i].image), VK_IMAGE_LAYOUT_UNDEFINED});
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