Commit 2761df72 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

wayland: Refactor dmabuf attributes in linux-dmabuf-v1

At the moment, dmabuf importing is scattered all over the place in kwin.
It would be great if we had one function that takes dma-buf attributes
and returns an EGLImage if successful.

As the first step, make linux-dmabuf-v1 implementation provide dmabuf
attrs compatible with KWin::DmaBufAttributes.
parent 00df0a70
......@@ -58,8 +58,9 @@ void DmabufFeedback::scanoutFailed(KWaylandServer::SurfaceInterface *surface, co
if (const auto &feedback = m_surface->dmabufFeedbackV1()) {
const auto buffer = qobject_cast<KWaylandServer::LinuxDmaBufV1ClientBuffer *>(surface->buffer());
Q_ASSERT(buffer);
if (!m_attemptedFormats[buffer->format()].contains(buffer->planes().first().modifier)) {
m_attemptedFormats[buffer->format()] << buffer->planes().first().modifier;
const KWaylandServer::LinuxDmaBufAttributes dmabufAttrs = buffer->attributes();
if (!m_attemptedFormats[dmabufAttrs.format].contains(dmabufAttrs.modifier)) {
m_attemptedFormats[dmabufAttrs.format] << dmabufAttrs.modifier;
QVector<KWaylandServer::LinuxDmaBufV1Feedback::Tranche> scanoutTranches;
const auto tranches = m_eglBackend->dmabuf()->tranches();
for (const auto &tranche : tranches) {
......
......@@ -152,29 +152,28 @@ void GbmBuffer::createFds()
std::shared_ptr<GbmBuffer> GbmBuffer::importBuffer(DrmGpu *gpu, KWaylandServer::LinuxDmaBufV1ClientBuffer *clientBuffer)
{
const auto planes = clientBuffer->planes();
const auto attrs = clientBuffer->attributes();
gbm_bo *bo;
if (planes.first().modifier != DRM_FORMAT_MOD_INVALID || planes.first().offset > 0 || planes.count() > 1) {
if (attrs.modifier != DRM_FORMAT_MOD_INVALID || attrs.offset[0] > 0 || attrs.planeCount > 1) {
gbm_import_fd_modifier_data data = {};
data.format = clientBuffer->format();
data.width = (uint32_t)clientBuffer->size().width();
data.height = (uint32_t)clientBuffer->size().height();
data.num_fds = planes.count();
data.modifier = planes.first().modifier;
for (int i = 0; i < planes.count(); i++) {
data.fds[i] = planes[i].fd;
data.offsets[i] = planes[i].offset;
data.strides[i] = planes[i].stride;
data.format = attrs.format;
data.width = static_cast<uint32_t>(attrs.width);
data.height = static_cast<uint32_t>(attrs.height);
data.num_fds = attrs.planeCount;
data.modifier = attrs.modifier;
for (int i = 0; i < attrs.planeCount; i++) {
data.fds[i] = attrs.fd[i];
data.offsets[i] = attrs.offset[i];
data.strides[i] = attrs.pitch[i];
}
bo = gbm_bo_import(gpu->gbmDevice(), GBM_BO_IMPORT_FD_MODIFIER, &data, GBM_BO_USE_SCANOUT);
} else {
const auto &plane = planes.first();
gbm_import_fd_data data = {};
data.fd = plane.fd;
data.width = (uint32_t)clientBuffer->size().width();
data.height = (uint32_t)clientBuffer->size().height();
data.stride = plane.stride;
data.format = clientBuffer->format();
data.fd = attrs.fd[0];
data.width = static_cast<uint32_t>(attrs.width);
data.height = static_cast<uint32_t>(attrs.height);
data.stride = attrs.pitch[0];
data.format = attrs.format;
bo = gbm_bo_import(gpu->gbmDevice(), GBM_BO_IMPORT_FD, &data, GBM_BO_USE_SCANOUT);
}
if (bo) {
......
......@@ -134,7 +134,7 @@ bool EglGbmLayer::scanout(SurfaceItem *surfaceItem)
return false;
}
const auto buffer = qobject_cast<KWaylandServer::LinuxDmaBufV1ClientBuffer *>(surface->buffer());
if (!buffer || buffer->planes().isEmpty() || buffer->size() != m_pipeline->bufferSize()) {
if (!buffer || buffer->size() != m_pipeline->bufferSize()) {
return false;
}
......
......@@ -155,7 +155,7 @@ bool VirtualEglGbmLayer::scanout(SurfaceItem *surfaceItem)
return false;
}
const auto buffer = qobject_cast<KWaylandServer::LinuxDmaBufV1ClientBuffer *>(item->surface()->buffer());
if (!buffer || buffer->planes().isEmpty() || buffer->size() != m_output->pixelSize()) {
if (!buffer || buffer->size() != m_output->pixelSize()) {
return false;
}
const auto scanoutBuffer = GbmBuffer::importBuffer(m_output->gpu(), buffer);
......
......@@ -13,11 +13,9 @@
namespace KWin
{
LinuxDmaBufV1ClientBuffer::LinuxDmaBufV1ClientBuffer(const QVector<KWaylandServer::LinuxDmaBufV1Plane> &planes,
quint32 format,
const QSize &size,
LinuxDmaBufV1ClientBuffer::LinuxDmaBufV1ClientBuffer(const KWaylandServer::LinuxDmaBufAttributes &attrs,
quint32 flags)
: KWaylandServer::LinuxDmaBufV1ClientBuffer(size, format, flags, planes)
: KWaylandServer::LinuxDmaBufV1ClientBuffer(attrs, flags)
{
waylandServer()->addLinuxDmabufBuffer(this);
}
......@@ -40,14 +38,10 @@ LinuxDmaBufV1RendererInterface::~LinuxDmaBufV1RendererInterface()
waylandServer()->linuxDmabuf()->setRendererInterface(nullptr);
}
KWaylandServer::LinuxDmaBufV1ClientBuffer *LinuxDmaBufV1RendererInterface::importBuffer(const QVector<KWaylandServer::LinuxDmaBufV1Plane> &planes,
quint32 format,
const QSize &size,
KWaylandServer::LinuxDmaBufV1ClientBuffer *LinuxDmaBufV1RendererInterface::importBuffer(const KWaylandServer::LinuxDmaBufAttributes &attrs,
quint32 flags)
{
Q_UNUSED(planes)
Q_UNUSED(format)
Q_UNUSED(size)
Q_UNUSED(attrs)
Q_UNUSED(flags)
return nullptr;
......
......@@ -18,9 +18,7 @@ namespace KWin
class KWIN_EXPORT LinuxDmaBufV1ClientBuffer : public KWaylandServer::LinuxDmaBufV1ClientBuffer
{
public:
LinuxDmaBufV1ClientBuffer(const QVector<KWaylandServer::LinuxDmaBufV1Plane> &planes,
quint32 format,
const QSize &size,
LinuxDmaBufV1ClientBuffer(const KWaylandServer::LinuxDmaBufAttributes &attrs,
quint32 flags);
~LinuxDmaBufV1ClientBuffer() override;
};
......@@ -31,9 +29,7 @@ public:
explicit LinuxDmaBufV1RendererInterface();
~LinuxDmaBufV1RendererInterface() override;
KWaylandServer::LinuxDmaBufV1ClientBuffer *importBuffer(const QVector<KWaylandServer::LinuxDmaBufV1Plane> &planes,
quint32 format,
const QSize &size,
KWaylandServer::LinuxDmaBufV1ClientBuffer *importBuffer(const KWaylandServer::LinuxDmaBufAttributes &attrs,
quint32 flags) override;
protected:
......
......@@ -91,23 +91,19 @@ YuvFormat yuvFormats[] = {
2}}}};
EglDmabufBuffer::EglDmabufBuffer(EGLImage image,
const QVector<KWaylandServer::LinuxDmaBufV1Plane> &planes,
uint32_t format,
const QSize &size,
const KWaylandServer::LinuxDmaBufAttributes &attrs,
quint32 flags,
EglDmabuf *interfaceImpl)
: EglDmabufBuffer(planes, format, size, flags, interfaceImpl)
: EglDmabufBuffer(attrs, flags, interfaceImpl)
{
m_importType = ImportType::Direct;
addImage(image);
}
EglDmabufBuffer::EglDmabufBuffer(const QVector<KWaylandServer::LinuxDmaBufV1Plane> &planes,
uint32_t format,
const QSize &size,
EglDmabufBuffer::EglDmabufBuffer(const KWaylandServer::LinuxDmaBufAttributes &attrs,
quint32 flags,
EglDmabuf *interfaceImpl)
: LinuxDmaBufV1ClientBuffer(planes, format, size, flags)
: LinuxDmaBufV1ClientBuffer(attrs, flags)
, m_interfaceImpl(interfaceImpl)
{
m_importType = ImportType::Conversion;
......@@ -136,63 +132,61 @@ void EglDmabufBuffer::removeImages()
m_images.clear();
}
EGLImage EglDmabuf::createImage(const QVector<KWaylandServer::LinuxDmaBufV1Plane> &planes,
uint32_t format,
const QSize &size)
EGLImage EglDmabuf::createImage(const KWaylandServer::LinuxDmaBufAttributes &attrs)
{
const bool hasModifiers = eglQueryDmaBufModifiersEXT != nullptr && planes[0].modifier != DRM_FORMAT_MOD_INVALID;
const bool hasModifiers = eglQueryDmaBufModifiersEXT != nullptr && attrs.modifier != DRM_FORMAT_MOD_INVALID;
QVector<EGLint> attribs;
attribs << EGL_WIDTH << size.width()
<< EGL_HEIGHT << size.height()
<< EGL_LINUX_DRM_FOURCC_EXT << EGLint(format)
attribs << EGL_WIDTH << attrs.width
<< EGL_HEIGHT << attrs.height
<< EGL_LINUX_DRM_FOURCC_EXT << EGLint(attrs.format)
<< EGL_DMA_BUF_PLANE0_FD_EXT << planes[0].fd
<< EGL_DMA_BUF_PLANE0_OFFSET_EXT << EGLint(planes[0].offset)
<< EGL_DMA_BUF_PLANE0_PITCH_EXT << EGLint(planes[0].stride);
<< EGL_DMA_BUF_PLANE0_FD_EXT << attrs.fd[0]
<< EGL_DMA_BUF_PLANE0_OFFSET_EXT << EGLint(attrs.offset[0])
<< EGL_DMA_BUF_PLANE0_PITCH_EXT << EGLint(attrs.pitch[0]);
if (hasModifiers) {
attribs
<< EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT << EGLint(planes[0].modifier & 0xffffffff)
<< EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT << EGLint(planes[0].modifier >> 32);
<< EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT << EGLint(attrs.modifier & 0xffffffff)
<< EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT << EGLint(attrs.modifier >> 32);
}
if (planes.count() > 1) {
if (attrs.planeCount > 1) {
attribs
<< EGL_DMA_BUF_PLANE1_FD_EXT << planes[1].fd
<< EGL_DMA_BUF_PLANE1_OFFSET_EXT << EGLint(planes[1].offset)
<< EGL_DMA_BUF_PLANE1_PITCH_EXT << EGLint(planes[1].stride);
<< EGL_DMA_BUF_PLANE1_FD_EXT << attrs.fd[1]
<< EGL_DMA_BUF_PLANE1_OFFSET_EXT << EGLint(attrs.offset[1])
<< EGL_DMA_BUF_PLANE1_PITCH_EXT << EGLint(attrs.pitch[1]);
if (hasModifiers) {
attribs
<< EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT << EGLint(planes[1].modifier & 0xffffffff)
<< EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT << EGLint(planes[1].modifier >> 32);
<< EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT << EGLint(attrs.modifier & 0xffffffff)
<< EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT << EGLint(attrs.modifier >> 32);
}
}
if (planes.count() > 2) {
if (attrs.planeCount > 2) {
attribs
<< EGL_DMA_BUF_PLANE2_FD_EXT << planes[2].fd
<< EGL_DMA_BUF_PLANE2_OFFSET_EXT << EGLint(planes[2].offset)
<< EGL_DMA_BUF_PLANE2_PITCH_EXT << EGLint(planes[2].stride);
<< EGL_DMA_BUF_PLANE2_FD_EXT << attrs.fd[2]
<< EGL_DMA_BUF_PLANE2_OFFSET_EXT << EGLint(attrs.offset[2])
<< EGL_DMA_BUF_PLANE2_PITCH_EXT << EGLint(attrs.pitch[2]);
if (hasModifiers) {
attribs
<< EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT << EGLint(planes[2].modifier & 0xffffffff)
<< EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT << EGLint(planes[2].modifier >> 32);
<< EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT << EGLint(attrs.modifier & 0xffffffff)
<< EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT << EGLint(attrs.modifier >> 32);
}
}
if (eglQueryDmaBufModifiersEXT != nullptr && planes.count() > 3) {
if (attrs.planeCount > 3) {
attribs
<< EGL_DMA_BUF_PLANE3_FD_EXT << planes[3].fd
<< EGL_DMA_BUF_PLANE3_OFFSET_EXT << EGLint(planes[3].offset)
<< EGL_DMA_BUF_PLANE3_PITCH_EXT << EGLint(planes[3].stride);
<< EGL_DMA_BUF_PLANE3_FD_EXT << attrs.fd[3]
<< EGL_DMA_BUF_PLANE3_OFFSET_EXT << EGLint(attrs.offset[3])
<< EGL_DMA_BUF_PLANE3_PITCH_EXT << EGLint(attrs.pitch[3]);
if (hasModifiers) {
attribs
<< EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT << EGLint(planes[3].modifier & 0xffffffff)
<< EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT << EGLint(planes[3].modifier >> 32);
<< EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT << EGLint(attrs.modifier & 0xffffffff)
<< EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT << EGLint(attrs.modifier >> 32);
}
}
......@@ -212,34 +206,30 @@ EGLImage EglDmabuf::createImage(const QVector<KWaylandServer::LinuxDmaBufV1Plane
return image;
}
KWaylandServer::LinuxDmaBufV1ClientBuffer *EglDmabuf::importBuffer(const QVector<KWaylandServer::LinuxDmaBufV1Plane> &planes,
quint32 format,
const QSize &size,
KWaylandServer::LinuxDmaBufV1ClientBuffer *EglDmabuf::importBuffer(const KWaylandServer::LinuxDmaBufAttributes &attrs,
quint32 flags)
{
Q_ASSERT(planes.count() > 0);
Q_ASSERT(attrs.planeCount > 0);
// Try first to import as a single image
if (auto *img = createImage(planes, format, size)) {
return new EglDmabufBuffer(img, planes, format, size, flags, this);
if (auto *img = createImage(attrs)) {
return new EglDmabufBuffer(img, attrs, flags, this);
}
// TODO: to enable this we must be able to store multiple textures per window pixmap
// and when on window draw do yuv to rgb transformation per shader (see Weston)
// // not a single image, try yuv import
// return yuvImport(planes, format, size, flags);
// return yuvImport(attrs, flags);
return nullptr;
}
KWaylandServer::LinuxDmaBufV1ClientBuffer *EglDmabuf::yuvImport(const QVector<KWaylandServer::LinuxDmaBufV1Plane> &planes,
quint32 format,
const QSize &size,
KWaylandServer::LinuxDmaBufV1ClientBuffer *EglDmabuf::yuvImport(const KWaylandServer::LinuxDmaBufAttributes &attrs,
quint32 flags)
{
YuvFormat yuvFormat;
for (YuvFormat f : yuvFormats) {
if (f.format == format) {
if (f.format == attrs.format) {
yuvFormat = f;
break;
}
......@@ -247,25 +237,25 @@ KWaylandServer::LinuxDmaBufV1ClientBuffer *EglDmabuf::yuvImport(const QVector<KW
if (yuvFormat.format == 0) {
return nullptr;
}
if (planes.count() != yuvFormat.inputPlanes) {
if (attrs.planeCount != yuvFormat.inputPlanes) {
return nullptr;
}
auto *buf = new EglDmabufBuffer(planes, format, size, flags, this);
auto *buf = new EglDmabufBuffer(attrs, flags, this);
for (int i = 0; i < yuvFormat.outputPlanes; i++) {
int planeIndex = yuvFormat.planes[i].planeIndex;
KWaylandServer::LinuxDmaBufV1Plane plane = {
planes[planeIndex].fd,
planes[planeIndex].offset,
planes[planeIndex].stride,
planes[planeIndex].modifier};
const auto planeFormat = yuvFormat.planes[i].format;
const auto planeSize = QSize(size.width() / yuvFormat.planes[i].widthDivisor,
size.height() / yuvFormat.planes[i].heightDivisor);
auto *image = createImage(QVector<KWaylandServer::LinuxDmaBufV1Plane>(1, plane),
planeFormat,
planeSize);
const int planeIndex = yuvFormat.planes[i].planeIndex;
const KWaylandServer::LinuxDmaBufAttributes planeAttrs {
.planeCount = 1,
.width = attrs.width / yuvFormat.planes[i].widthDivisor,
.height = attrs.height / yuvFormat.planes[i].heightDivisor,
.format = yuvFormat.planes[i].format,
.modifier = attrs.modifier,
.fd = {attrs.fd[planeIndex], -1, -1, -1},
.offset = {attrs.offset[planeIndex], 0, 0, 0},
.pitch = {attrs.pitch[planeIndex], 0, 0, 0},
};
auto *image = createImage(planeAttrs);
if (!image) {
delete buf;
return nullptr;
......@@ -301,7 +291,7 @@ EglDmabuf::EglDmabuf(AbstractEglBackend *backend)
for (auto *buffer : prevBuffersSet) {
auto *buf = static_cast<EglDmabufBuffer *>(buffer);
buf->setInterfaceImplementation(this);
buf->addImage(createImage(buf->planes(), buf->format(), buf->size()));
buf->addImage(createImage(buf->attributes()));
}
setSupportedFormatsAndModifiers();
}
......
......@@ -28,15 +28,11 @@ public:
};
EglDmabufBuffer(EGLImage image,
const QVector<KWaylandServer::LinuxDmaBufV1Plane> &planes,
quint32 format,
const QSize &size,
const KWaylandServer::LinuxDmaBufAttributes &attrs,
quint32 flags,
EglDmabuf *interfaceImpl);
EglDmabufBuffer(const QVector<KWaylandServer::LinuxDmaBufV1Plane> &planes,
quint32 format,
const QSize &size,
EglDmabufBuffer(const KWaylandServer::LinuxDmaBufAttributes &attrs,
quint32 flags,
EglDmabuf *interfaceImpl);
......@@ -65,9 +61,7 @@ public:
explicit EglDmabuf(AbstractEglBackend *backend);
~EglDmabuf() override;
KWaylandServer::LinuxDmaBufV1ClientBuffer *importBuffer(const QVector<KWaylandServer::LinuxDmaBufV1Plane> &planes,
quint32 format,
const QSize &size,
KWaylandServer::LinuxDmaBufV1ClientBuffer *importBuffer(const KWaylandServer::LinuxDmaBufAttributes &attrs,
quint32 flags) override;
QVector<KWaylandServer::LinuxDmaBufV1Feedback::Tranche> tranches() const
......@@ -76,13 +70,9 @@ public:
}
private:
EGLImage createImage(const QVector<KWaylandServer::LinuxDmaBufV1Plane> &planes,
uint32_t format,
const QSize &size);
EGLImage createImage(const KWaylandServer::LinuxDmaBufAttributes &attrs);
KWaylandServer::LinuxDmaBufV1ClientBuffer *yuvImport(const QVector<KWaylandServer::LinuxDmaBufV1Plane> &planes,
quint32 format,
const QSize &size,
KWaylandServer::LinuxDmaBufV1ClientBuffer *yuvImport(const KWaylandServer::LinuxDmaBufAttributes &attrs,
quint32 flags);
void setSupportedFormatsAndModifiers();
......
......@@ -87,15 +87,14 @@ void LinuxDmaBufV1ClientBufferIntegrationPrivate::zwp_linux_dmabuf_v1_create_par
LinuxDmaBufParamsV1::LinuxDmaBufParamsV1(LinuxDmaBufV1ClientBufferIntegration *integration, ::wl_resource *resource)
: QtWaylandServer::zwp_linux_buffer_params_v1(resource)
, m_integration(integration)
, m_planes(4)
{
}
LinuxDmaBufParamsV1::~LinuxDmaBufParamsV1()
{
for (const LinuxDmaBufV1Plane &plane : m_planes) {
if (plane.fd != -1) {
close(plane.fd);
for (int i = 0; i < m_attrs.planeCount; ++i) {
if (m_attrs.fd[i] != -1) {
close(m_attrs.fd[i]);
}
}
}
......@@ -125,26 +124,23 @@ void LinuxDmaBufParamsV1::zwp_linux_buffer_params_v1_add(Resource *resource,
return;
}
if (Q_UNLIKELY(plane_idx >= uint(m_planes.size()))) {
if (Q_UNLIKELY(plane_idx >= 4)) {
wl_resource_post_error(resource->handle, error_plane_idx, "plane index %d is out of bounds", plane_idx);
close(fd);
return;
}
LinuxDmaBufV1Plane &plane = m_planes[plane_idx];
if (Q_UNLIKELY(plane.fd != -1)) {
if (Q_UNLIKELY(m_attrs.fd[plane_idx] != -1)) {
wl_resource_post_error(resource->handle, error_plane_set, "the plane index %d was already set", plane_idx);
close(fd);
return;
}
plane.fd = fd;
plane.modifier = (quint64(modifier_hi) << 32) | modifier_lo;
plane.offset = offset;
plane.stride = stride;
m_planeCount++;
m_attrs.fd[plane_idx] = fd;
m_attrs.offset[plane_idx] = offset;
m_attrs.pitch[plane_idx] = stride;
m_attrs.modifier = (quint64(modifier_hi) << 32) | modifier_lo;
m_attrs.planeCount++;
}
void LinuxDmaBufParamsV1::zwp_linux_buffer_params_v1_create(Resource *resource, int32_t width, int32_t height, uint32_t format, uint32_t flags)
......@@ -159,15 +155,18 @@ void LinuxDmaBufParamsV1::zwp_linux_buffer_params_v1_create(Resource *resource,
}
m_isUsed = true;
m_planes.resize(m_planeCount);
LinuxDmaBufV1ClientBuffer *clientBuffer = m_integration->rendererInterface()->importBuffer(m_planes, format, QSize(width, height), flags);
m_attrs.width = width;
m_attrs.height = height;
m_attrs.format = format;
LinuxDmaBufV1ClientBuffer *clientBuffer = m_integration->rendererInterface()->importBuffer(m_attrs, flags);
if (!clientBuffer) {
send_failed(resource->handle);
return;
}
m_planes.clear(); // the ownership of file descriptors has been moved to the buffer
m_attrs = LinuxDmaBufAttributes{}; // the ownership of file descriptors has been moved to the buffer
wl_resource *bufferResource = wl_resource_create(resource->client(), &wl_buffer_interface, 1, 0);
if (!bufferResource) {
......@@ -200,15 +199,18 @@ void LinuxDmaBufParamsV1::zwp_linux_buffer_params_v1_create_immed(Resource *reso
}
m_isUsed = true;
m_planes.resize(m_planeCount);
LinuxDmaBufV1ClientBuffer *clientBuffer = m_integration->rendererInterface()->importBuffer(m_planes, format, QSize(width, height), flags);
m_attrs.width = width;
m_attrs.height = height;
m_attrs.format = format;
LinuxDmaBufV1ClientBuffer *clientBuffer = m_integration->rendererInterface()->importBuffer(m_attrs, flags);
if (!clientBuffer) {
wl_resource_post_error(resource->handle, error_invalid_wl_buffer, "importing the supplied dmabufs failed");
return;
}
m_planes.clear(); // the ownership of file descriptors has been moved to the buffer
m_attrs = LinuxDmaBufAttributes{}; // the ownership of file descriptors has been moved to the buffer
wl_resource *bufferResource = wl_resource_create(resource->client(), &wl_buffer_interface, 1, buffer_id);
if (!bufferResource) {
......@@ -225,14 +227,14 @@ void LinuxDmaBufParamsV1::zwp_linux_buffer_params_v1_create_immed(Resource *reso
bool LinuxDmaBufParamsV1::test(Resource *resource, uint32_t width, uint32_t height)
{
if (Q_UNLIKELY(!m_planeCount)) {
if (Q_UNLIKELY(!m_attrs.planeCount)) {
wl_resource_post_error(resource->handle, error_incomplete, "no planes have been specified");
return false;
}
// Check for holes in the dmabuf set (e.g. [0, 1, 3]).
for (int i = 0; i < m_planeCount; ++i) {
if (m_planes[i].fd == -1) {
for (int i = 0; i < m_attrs.planeCount; ++i) {
if (m_attrs.fd[i] == -1) {
wl_resource_post_error(resource->handle, error_incomplete, "no dmabuf has been added for plane %d", i);
return false;
}
......@@ -243,40 +245,38 @@ bool LinuxDmaBufParamsV1::test(Resource *resource, uint32_t width, uint32_t heig
return false;
}
for (int i = 0; i < m_planeCount; ++i) {
const LinuxDmaBufV1Plane &plane = m_planes.at(i);
for (int i = 0; i < m_attrs.planeCount; ++i) {
// Check for overflows.
if (Q_UNLIKELY(uint64_t(plane.offset) + plane.stride > UINT32_MAX)) {
if (Q_UNLIKELY(uint64_t(m_attrs.offset[i]) + m_attrs.pitch[i] > UINT32_MAX)) {
wl_resource_post_error(resource->handle, error_out_of_bounds, "size overflow for plane %d", i);
return false;
}
if (Q_UNLIKELY(i == 0 && uint64_t(plane.offset) + uint64_t(plane.stride) * height > UINT32_MAX)) {
if (Q_UNLIKELY(i == 0 && uint64_t(m_attrs.offset[i]) + uint64_t(m_attrs.pitch[i]) * height > UINT32_MAX)) {
wl_resource_post_error(resource->handle, error_out_of_bounds, "size overflow for plane %d", i);
return false;
}
// Don't report an error as it might be caused by the kernel not supporting
// seeking on dmabuf.
const off_t size = lseek(plane.fd, 0, SEEK_END);
const off_t size = lseek(m_attrs.fd[i], 0, SEEK_END);
if (size == -1) {
continue;
}
if (Q_UNLIKELY(plane.offset >= size)) {
wl_resource_post_error(resource->handle, error_out_of_bounds, "invalid offset %i for plane %d", plane.offset, i);
if (Q_UNLIKELY(m_attrs.offset[i] >= size)) {
wl_resource_post_error(resource->handle, error_out_of_bounds, "invalid offset %i for plane %d", m_attrs.offset[i], i);
return false;
}
if (Q_UNLIKELY(plane.offset + plane.stride > size)) {
wl_resource_post_error(resource->handle, error_out_of_bounds, "invalid stride %i for plane %d", plane.stride, i);
if (Q_UNLIKELY(m_attrs.offset[i] + m_attrs.pitch[i] > size)) {
wl_resource_post_error(resource->handle, error_out_of_bounds, "invalid stride %i for plane %d", m_attrs.pitch[i], i);
return false;
}
// Only valid for first plane as other planes might be sub-sampled according to
// fourcc format.
if (Q_UNLIKELY(i == 0 && plane.offset + plane.stride * height > size)) {
if (Q_UNLIKELY(i == 0 && m_attrs.offset[i] + m_attrs.pitch[i] * height > size)) {
wl_resource_post_error(resource->handle, error_out_of_bounds, "invalid buffer stride of height for plane %d", i);
return false;
}
......@@ -366,24 +366,22 @@ void LinuxDmaBufV1ClientBufferPrivate::buffer_destroy(Resource *resource)
wl_resource_destroy(resource->handle);
}
LinuxDmaBufV1ClientBuffer::LinuxDmaBufV1ClientBuffer(const QSize &size, quint32 format, quint32 flags, const QVector<LinuxDmaBufV1Plane> &planes)
LinuxDmaBufV1ClientBuffer::LinuxDmaBufV1ClientBuffer(const LinuxDmaBufAttributes &attrs, quint32 flags)
: ClientBuffer(*new LinuxDmaBufV1ClientBufferPrivate)
{
Q_D(LinuxDmaBufV1ClientBuffer);