6 #include "buffer_interface.h"
8 #include "linuxdmabuf_v1_interface.h"
10 #include "surface_interface.h"
12 #include <wayland-server.h>
15 #include <QtGui/qopengl.h>
17 #include "drm_fourcc.h"
25 typedef EGLBoolean (*eglQueryWaylandBufferWL_func)(EGLDisplay dpy,
struct wl_resource *buffer, EGLint attribute, EGLint *value);
26 eglQueryWaylandBufferWL_func eglQueryWaylandBufferWL =
nullptr;
29 class BufferInterface::Private
32 Private(BufferInterface *q, wl_resource *
resource, SurfaceInterface *
parent);
38 LinuxDmabufBuffer *dmabufBuffer;
44 static BufferInterface *
get(wl_resource *r);
47 static void destroyListenerCallback(wl_listener *listener,
void *
data);
48 static Private *cast(wl_resource *r);
49 static void imageBufferCleanupHandler(
void *info);
51 static Private *s_accessedBuffer;
52 static int s_accessCounter;
59 BufferInterface::Private *BufferInterface::Private::s_accessedBuffer =
nullptr;
60 int BufferInterface::Private::s_accessCounter = 0;
62 BufferInterface::Private *BufferInterface::Private::cast(wl_resource *r)
64 auto it = std::find_if(s_buffers.constBegin(), s_buffers.constEnd(), [r](Private *d) {
65 return d->buffer == r;
67 if (it == s_buffers.constEnd()) {
82 void BufferInterface::Private::imageBufferCleanupHandler(
void *info)
84 Private *p =
reinterpret_cast<Private *
>(info);
85 Q_ASSERT(p == s_accessedBuffer);
86 Q_ASSERT(s_accessCounter > 0);
88 if (s_accessCounter == 0) {
89 s_accessedBuffer =
nullptr;
91 wl_shm_buffer_end_access(p->shmBuffer);
94 BufferInterface::Private::Private(BufferInterface *q, wl_resource *resource, SurfaceInterface *parent)
96 , shmBuffer(wl_shm_buffer_get(resource))
97 , dmabufBuffer(nullptr)
103 if (!shmBuffer && wl_resource_instance_of(resource, &wl_buffer_interface, LinuxDmabufUnstableV1Interface::bufferImplementation())) {
104 dmabufBuffer =
static_cast<LinuxDmabufBuffer *
>(wl_resource_get_user_data(resource));
107 listener.notify = destroyListenerCallback;
108 listener.link.prev =
nullptr;
109 listener.link.next =
nullptr;
110 wl_resource_add_destroy_listener(resource, &listener);
112 size =
QSize(wl_shm_buffer_get_width(shmBuffer), wl_shm_buffer_get_height(shmBuffer));
114 switch (wl_shm_buffer_get_format(shmBuffer)) {
115 case WL_SHM_FORMAT_ARGB8888:
118 case WL_SHM_FORMAT_XRGB8888:
123 }
else if (dmabufBuffer) {
124 switch (dmabufBuffer->format()) {
125 case DRM_FORMAT_ARGB4444:
126 case DRM_FORMAT_ABGR4444:
127 case DRM_FORMAT_RGBA4444:
128 case DRM_FORMAT_BGRA4444:
130 case DRM_FORMAT_ARGB1555:
131 case DRM_FORMAT_ABGR1555:
132 case DRM_FORMAT_RGBA5551:
133 case DRM_FORMAT_BGRA5551:
135 case DRM_FORMAT_ARGB8888:
136 case DRM_FORMAT_ABGR8888:
137 case DRM_FORMAT_RGBA8888:
138 case DRM_FORMAT_BGRA8888:
140 case DRM_FORMAT_ARGB2101010:
141 case DRM_FORMAT_ABGR2101010:
142 case DRM_FORMAT_RGBA1010102:
143 case DRM_FORMAT_BGRA1010102:
145 case DRM_FORMAT_XRGB8888_A8:
146 case DRM_FORMAT_XBGR8888_A8:
147 case DRM_FORMAT_RGBX8888_A8:
148 case DRM_FORMAT_BGRX8888_A8:
149 case DRM_FORMAT_RGB888_A8:
150 case DRM_FORMAT_BGR888_A8:
151 case DRM_FORMAT_RGB565_A8:
152 case DRM_FORMAT_BGR565_A8:
159 size = dmabufBuffer->size();
161 EGLDisplay eglDisplay = parent->global()->display()->eglDisplay();
162 static bool resolved =
false;
164 if (!resolved && eglDisplay != EGL_NO_DISPLAY) {
165 eglQueryWaylandBufferWL = (eglQueryWaylandBufferWL_func)eglGetProcAddress(
"eglQueryWaylandBufferWL");
168 if (eglQueryWaylandBufferWL) {
172 valid = eglQueryWaylandBufferWL(eglDisplay, buffer, EGL_WIDTH, &width);
173 valid = valid && eglQueryWaylandBufferWL(eglDisplay, buffer, EGL_HEIGHT, &height);
179 if (eglQueryWaylandBufferWL(eglDisplay, buffer, EGL_TEXTURE_FORMAT, &
format)) {
181 case EGL_TEXTURE_RGBA:
184 case EGL_TEXTURE_RGB:
194 BufferInterface::Private::~Private()
196 wl_list_remove(&listener.link);
197 s_buffers.removeAll(
this);
210 return new BufferInterface(r,
nullptr);
213 BufferInterface::BufferInterface(wl_resource *resource, SurfaceInterface *parent)
215 , d(new Private(this, resource, parent))
219 BufferInterface::~BufferInterface()
221 if (d->refCount != 0) {
222 qCWarning(KWAYLAND_SERVER) <<
"Buffer destroyed while still being referenced, ref count:" << d->refCount;
226 void BufferInterface::Private::destroyListenerCallback(wl_listener *listener,
void *data)
229 auto b = cast(
reinterpret_cast<wl_resource *
>(data));
231 Q_EMIT b->q->aboutToBeDestroyed(b->q);
235 void BufferInterface::ref()
240 void BufferInterface::unref()
242 Q_ASSERT(d->refCount > 0);
244 if (d->refCount == 0) {
246 wl_buffer_send_release(d->buffer);
247 wl_client_flush(wl_resource_get_client(d->buffer));
258 switch (wl_shm_buffer_get_format(shmBuffer)) {
259 case WL_SHM_FORMAT_ARGB8888:
261 case WL_SHM_FORMAT_XRGB8888:
270 return d->createImage();
273 QImage BufferInterface::Private::createImage()
278 if (s_accessedBuffer !=
nullptr && s_accessedBuffer !=
this) {
285 s_accessedBuffer =
this;
287 wl_shm_buffer_begin_access(shmBuffer);
288 return QImage((
const uchar *)wl_shm_buffer_get_data(shmBuffer),
291 wl_shm_buffer_get_stride(shmBuffer),
293 &imageBufferCleanupHandler,
297 bool BufferInterface::isReferenced()
const
299 return d->refCount > 0;
307 wl_shm_buffer *BufferInterface::shmBuffer()
314 return d->dmabufBuffer;
317 wl_resource *BufferInterface::resource()
const
327 void BufferInterface::setSize(
const QSize &size)
329 if (d->shmBuffer || d->size == size) {
333 Q_EMIT sizeChanged();
336 bool BufferInterface::hasAlphaChannel()
const