5#include <qeglfskmshelpers_p.h>
8#include <QtCore/QLoggingCategory>
10#include <drm_fourcc.h>
14Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
17static inline uint drmFormatToV4l2PixelFormat(uint drmFormat) {
19 Q_ASSERT(DRM_FORMAT_ARGB8888 == V4L2_PIX_FMT_ABGR32);
26 case DRM_FORMAT_RGB888:
27 return MEDIA_BUS_FMT_RGB888_1X24;
28 case DRM_FORMAT_BGR888:
29 return MEDIA_BUS_FMT_BGR888_1X24;
30 case DRM_FORMAT_XRGB8888:
31 case DRM_FORMAT_XBGR8888:
33 case DRM_FORMAT_RGBX8888:
34 case DRM_FORMAT_BGRX8888:
35 case DRM_FORMAT_ARGB8888:
36 case DRM_FORMAT_ABGR8888:
37 case DRM_FORMAT_RGBA8888:
38 case DRM_FORMAT_BGRA8888:
39 return MEDIA_BUS_FMT_ARGB8888_1X32;
41 qWarning() <<
"Unknown drm format" << q_fourccToString(drmFormat) <<
"defaulting to argb8888";
42 return MEDIA_BUS_FMT_ARGB8888_1X32;
47 : m_mediaDevice(
"/dev/media0")
51 QString deviceName = md.deviceName();
53 if (md.model() != QString(
"VSP2"))
54 qWarning() <<
"Unsupported media device model:" << md.model();
56 if (deviceName !=
"fe960000.vsp")
57 qWarning() <<
"Unknown media device name:" << deviceName;
59 const int numInputs = 5;
61 for (
int i = 0; i < numInputs; ++i) {
63 input.linkToBru = md.parseLink(QString(
"'%1 rpf.%2':1 -> '%1 bru':%2").arg(deviceName).arg(i));
64 input.inputFormatPad = md.parsePad(QString(
"'%1 rpf.%2':0").arg(deviceName).arg(i));
65 input.outputFormatPad = md.parsePad(QString(
"'%1 rpf.%2':1").arg(deviceName).arg(i));
67 input.bruInputFormatPad = md.parsePad(QString(
"'%1 bru':%2").arg(deviceName).arg(i));
69 m_inputs.append(input);
75 md
.enableLink(md.parseLink(QString(
"'%1 bru':5 -> '%1 wpf.0':0").arg(deviceName))
);
76 md
.enableLink(md.parseLink(QString(
"'%1 wpf.0':1 -> '%1 wpf.0 output':0").arg(deviceName))
);
79 auto bruOutputFormatPad = md.parsePad(QString(
"'%1 bru':5").arg(deviceName));
80 auto wpfInputFormatPad = md.parsePad(QString(
"'%1 wpf.0':0").arg(deviceName));
81 auto wpfOutputFormatPad = md.parsePad(QString(
"'%1 wpf.0':1").arg(deviceName));
83 m_wpfOutput->setFormat(screenSize);
84 QLinuxMediaDevice::setSubdevFormat(bruOutputFormatPad, screenSize);
85 QLinuxMediaDevice::setSubdevFormat(wpfInputFormatPad, screenSize);
86 QLinuxMediaDevice::setSubdevFormat(wpfOutputFormatPad, screenSize);
93 qCDebug(qLcEglfsKmsDebug) <<
"Blend unit: Enabling input" << i;
94 if (m_inputs[i].enabled) {
95 qWarning(
"Vsp2: Input %d already enabled", i);
99 if (!bufferGeometry.isValid()) {
100 qWarning() <<
"Vsp2: Invalid buffer geometry";
104 Input &input = m_inputs[i];
108 uint pixelFormat = drmFormatToV4l2PixelFormat(drmFormat);
109 if (!setInputFormat(i, bufferGeometry, pixelFormat, bytesPerLine)) {
120 for (
int i = 0; i < m_inputs.size(); ++i) {
121 if (!m_inputs[i].enabled)
122 return enableInput(i, bufferGeometry, drmFormat, bytesPerLine) ? i : -1;
124 qWarning() <<
"Vsp2: No more inputs available in blend unit";
130 qCDebug(qLcEglfsKmsDebug) <<
"Vsp2: disabling input" << i;
131 if (!m_inputs[i].enabled) {
132 qWarning(
"Vsp2: Input %d already disabled", i);
135 m_mediaDevice.disableLink(m_inputs[i].linkToBru);
136 m_inputs[i].rpfInput->clearBuffers();
137 m_inputs[i].enabled =
false;
143 Input &input = m_inputs[index];
145 if (!input.enabled) {
146 qWarning() <<
"Vsp2: Can't queue on disabled input" << index;
151 if (input.dmabuf.fd != dmabufFd) {
153 input.dmabuf.fd = dmabufFd;
160 Input &input = m_inputs[index];
162 if (input.geometry.topLeft() == position)
166 input.geometry.moveTopLeft(position);
172 Input &input = m_inputs[index];
173 if (input.alpha == alpha)
178 return QLinuxMediaDevice::setSubdevAlpha(input.outputFormatFd, alpha);
184 qWarning(
"Blending without being dirty, should not be necessary");
187 qWarning(
"Vsp2: Can't blend when layers are not enabled in order from 0 without gaps.");
191 bool queueingFailed =
false;
193 for (
int i=0; i < m_inputs.size(); ++i) {
194 auto &input = m_inputs[i];
196 if (!input.rpfInput->queueBuffer(input.dmabuf.fd, input.dmabuf.bytesUsed, input.dmabuf.length)) {
197 qWarning() <<
"Vsp2: Failed to queue buffer for input" << i
198 <<
"with dmabuf" << input.dmabuf.fd
199 <<
"and size" << input.geometry.size();
201 queueingFailed =
true;
206 if (queueingFailed) {
207 qWarning() <<
"Vsp2: Trying to clean up queued buffers";
208 for (
auto &input : std::as_const(m_inputs)) {
210 if (!input.rpfInput->clearBuffers())
211 qWarning() <<
"Vsp2: Failed to remove buffers after an aborted blend";
217 if (!m_wpfOutput->queueBuffer(outputDmabufFd, m_screenSize)) {
218 qWarning() <<
"Vsp2: Failed to queue blending output buffer" << outputDmabufFd << m_screenSize;
223 qWarning() <<
"Vsp2: Failed to start streaming";
228 qWarning() <<
"Vsp2: Failed to dequeue blending output buffer";
230 qWarning() <<
"Vsp2: Failed to stop streaming when recovering after a broken blend.";
235 qWarning() <<
"Vsp2: Failed to stop streaming";
245 return m_inputs.size();
250 bool seenDisabled =
false;
251 for (
auto &input : std::as_const(m_inputs)) {
252 if (seenDisabled && input.enabled)
254 seenDisabled |= !input.enabled;
256 return m_inputs[0].enabled;
261 for (
auto &input : m_inputs) {
263 if (!input.rpfInput->streamOn()) {
276 for (
auto &input : m_inputs) {
278 succeeded &= input.rpfInput->streamOff();
283bool QVsp2BlendingDevice::setInputFormat(
int i,
const QRect &bufferGeometry, uint pixelFormat, uint bytesPerLine)
285 Input &input = m_inputs[i];
287 Q_ASSERT(bufferGeometry.isValid());
290 input.enabled =
true;
291 input.geometry = bufferGeometry;
292 input.dmabuf.bytesUsed = bpp *
static_cast<uint>(bufferGeometry.width()) *
static_cast<uint>(bufferGeometry.height());
293 input.dmabuf.length =
static_cast<uint>(bufferGeometry.height()) * bytesPerLine;
295 const QSize size = bufferGeometry.size();
297 if (!input.rpfInput->setFormat(size, pixelFormat, bytesPerLine))
300 const uint mediaBusFormat = drmFormatToMediaBusFormat(pixelFormat);
301 if (!QLinuxMediaDevice::setSubdevFormat(input.inputFormatPad, size, mediaBusFormat))
304 if (!QLinuxMediaDevice::setSubdevFormat(input.outputFormatPad, size, mediaBusFormat))
307 if (!QLinuxMediaDevice::setSubdevFormat(input.bruInputFormatPad, size, mediaBusFormat))
QVsp2BlendingDevice(const QSize &screenSize)
int enableInput(const QRect &bufferGeometry, uint drmFormat, uint bytesPerLine)
bool blend(int outputDmabufFd)
bool hasContinuousLayers() const
bool setInputBuffer(int index, int dmabufFd)
bool enableInput(int i, const QRect &bufferGeometry, uint drmFormat, uint bytesPerLine)
bool setInputPosition(int index, const QPoint &position)
bool setInputAlpha(int index, qreal alpha)
static uint drmFormatToMediaBusFormat(uint drmFormat)