summaryrefslogtreecommitdiffstats
path: root/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>2015-10-27 18:03:44 +0100
committerLaszlo Agocs <laszlo.agocs@theqtcompany.com>2015-10-27 18:31:47 +0100
commit8cac11fd8398b91300af6b40d16fcfebafade622 (patch)
tree556717d1c8624fd691d52c441ff11bdda7cea731 /src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
parent699c44e3dc2d7099fdd87060c39309e318c55616 (diff)
parentf242587cbf3ee8ade683414aaa95158a1149db4c (diff)
Merge branch '5.6' into wip-compositor-api
qwindow-compositor changes from 5.6 will be adapted separately. The traditional wayland-egl path is tested and is functional like before. The EGLStream support will be verified separately once the qwindow-compositor changes are ready. Conflicts: examples/wayland/qwindow-compositor/qwindowcompositor.cpp examples/wayland/qwindow-compositor/textureblitter.cpp examples/wayland/qwindow-compositor/textureblitter.h examples/wayland/server-buffer/client/client.pro examples/wayland/server-buffer/compositor/compositor.pro src/compositor/compositor_api/qwaylandbufferref.cpp src/compositor/compositor_api/qwaylandbufferref.h src/compositor/hardware_integration/qwlclientbufferintegration_p.h src/compositor/wayland_wrapper/qwlkeyboard.cpp src/compositor/wayland_wrapper/qwlkeyboard_p.h src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h src/plugins/hardwareintegration/compositor/wayland-egl/wayland-egl.pro Change-Id: Ic2e3a6e8f74606c35b1e27cd4016fa133527d7ba
Diffstat (limited to 'src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp')
-rw-r--r--src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp229
1 files changed, 201 insertions, 28 deletions
diff --git a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
index d0e66362d..5cea48a43 100644
--- a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
+++ b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
@@ -43,11 +43,16 @@
#include <qpa/qplatformscreen.h>
#include <QtGui/QWindow>
#include <QtCore/QPointer>
-
#include <QDebug>
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
+#include <QMutex>
+#include <QMutexLocker>
+#include <QtCore/private/qcore_unix_p.h>
+#include <QtPlatformSupport/private/qeglstreamconvenience_p.h>
+
+#ifndef GL_TEXTURE_EXTERNAL_OES
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#endif
/* Needed for compatibility with Mesa older than 10.0. */
typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL_compat) (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
@@ -69,6 +74,28 @@ typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenu
QT_BEGIN_NAMESPACE
+struct BufferState
+{
+ BufferState()
+ : gl_texture(0)
+ , gl_texture_target(GL_TEXTURE_2D)
+ , egl_stream(EGL_NO_STREAM_KHR)
+ , isYInverted(true)
+ {}
+
+ GLuint gl_texture;
+ GLenum gl_texture_target;
+ EGLStreamKHR egl_stream;
+ bool isYInverted;
+ QSize size;
+};
+
+struct buffer_destroy_listener
+{
+ struct wl_listener listener;
+ class WaylandEglClientBufferIntegrationPrivate *d;
+};
+
class WaylandEglClientBufferIntegrationPrivate
{
public:
@@ -82,10 +109,40 @@ public:
, egl_create_image(0)
, egl_destroy_image(0)
, gl_egl_image_target_texture_2d(0)
- { }
+ , funcs(Q_NULLPTR)
+ {
+ destroy_listener.d = this;
+ destroy_listener.listener.notify = destroy_listener_callback;
+ }
+
+ static void destroy_listener_callback(wl_listener *listener, void *data) {
+ static QMutex mutex;
+ QMutexLocker locker(&mutex);
+
+ buffer_destroy_listener *destroy_listener = reinterpret_cast<buffer_destroy_listener *>(listener);
+ WaylandEglClientBufferIntegrationPrivate *self = destroy_listener->d;
+ struct ::wl_resource *buffer = static_cast<struct ::wl_resource *>(data);
+ if (!self->buffers.contains(buffer))
+ return;
+
+ Q_ASSERT(self);
+ Q_ASSERT(buffer);
+
+ BufferState state = self->buffers.take(buffer);
+
+ if (state.gl_texture != 0)
+ glDeleteTextures(1, &state.gl_texture);
+
+ if (state.egl_stream != EGL_NO_STREAM_KHR)
+ self->funcs->destroy_stream(self->egl_display, state.egl_stream);
+ }
+
EGLDisplay egl_display;
bool valid;
bool display_bound;
+ QHash<struct ::wl_resource *, BufferState> buffers;
+ buffer_destroy_listener destroy_listener;
+
PFNEGLBINDWAYLANDDISPLAYWL egl_bind_wayland_display;
PFNEGLUNBINDWAYLANDDISPLAYWL egl_unbind_wayland_display;
PFNEGLQUERYWAYLANDBUFFERWL_compat egl_query_wayland_buffer;
@@ -94,6 +151,8 @@ public:
PFNEGLDESTROYIMAGEKHRPROC egl_destroy_image;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC gl_egl_image_target_texture_2d;
+
+ QEGLStreamConvenience *funcs;
};
WaylandEglClientBufferIntegration::WaylandEglClientBufferIntegration()
@@ -158,52 +217,156 @@ void WaylandEglClientBufferIntegration::initializeHardware(struct wl_display *di
}
}
+ d->funcs = new QEGLStreamConvenience;
+ d->funcs->initialize(d->egl_display);
+
d->valid = true;
}
-void WaylandEglClientBufferIntegration::bindTextureToBuffer(struct ::wl_resource *buffer)
+static GLuint make_texture(GLenum target)
+{
+ GLuint texture;
+
+ glGenTextures(1, &texture);
+ glBindTexture(target, texture);
+
+ return texture;
+}
+
+static void set_texture_params(GLenum target)
+{
+ glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+}
+
+void WaylandEglClientBufferIntegration::initializeBuffer(struct ::wl_resource *buffer)
{
Q_D(WaylandEglClientBufferIntegration);
+ if (wl_shm_buffer_get(buffer))
+ return;
+
+ if (!buffer || d->buffers.contains(buffer))
+ return;
+
+ wl_signal_add(&buffer->destroy_signal, &d->destroy_listener.listener);
+}
+
+int WaylandEglClientBufferIntegration::textureTargetForBuffer(struct ::wl_resource *buffer) const
+{
+ Q_D(const WaylandEglClientBufferIntegration);
+
+ return d->buffers.value(buffer).gl_texture_target;
+}
+
+void WaylandEglClientBufferIntegration::bindTextureToBuffer(struct ::wl_resource *buffer)
+{
+ Q_D(WaylandEglClientBufferIntegration);
if (!d->valid) {
qWarning("QtCompositor: bindTextureToBuffer() failed");
return;
}
- // Vivante drivers on the iMX6 don't resolve this function early enough for us, they seem to require the EGL/GLES setup to be further
- // along than they are in initializeHardware(), so do the lookup here instead.
- if (!d->gl_egl_image_target_texture_2d)
- d->gl_egl_image_target_texture_2d = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
-
- if (!d->gl_egl_image_target_texture_2d) {
- qWarning("QtCompositor: bindTextureToBuffer() failed. Could not find glEGLImageTargetTexture2DOES.");
+ if (!buffer)
return;
+
+ BufferState state = d->buffers.value(buffer);
+
+ if (state.egl_stream != EGL_NO_STREAM_KHR) {
+ d->funcs->stream_consumer_acquire(d->egl_display, state.egl_stream);
+ } else {
+ Q_ASSERT(QOpenGLContext::currentContext());
+
+ EGLint format;
+ EGLNativeFileDescriptorKHR streamFd = EGL_NO_FILE_DESCRIPTOR_KHR;
+
+ EGLint width, height;
+ d->egl_query_wayland_buffer(d->egl_display, buffer, EGL_WIDTH, &width);
+ d->egl_query_wayland_buffer(d->egl_display, buffer, EGL_HEIGHT, &height);
+ state.size = QSize(width, height);
+
+#if defined(EGL_WAYLAND_Y_INVERTED_WL)
+ EGLint isYInverted;
+ EGLBoolean ret = d->egl_query_wayland_buffer(d->egl_display, buffer, EGL_WAYLAND_Y_INVERTED_WL, &isYInverted);
+ // Yes, this looks strange, but the specification says that EGL_FALSE return
+ // value (not supported) should be treated the same as EGL_TRUE return value
+ // and EGL_TRUE in value.
+ state.isYInverted = (ret == EGL_FALSE || isYInverted == EGL_TRUE);
+#endif
+
+ if (d->egl_query_wayland_buffer(d->egl_display, buffer, EGL_TEXTURE_FORMAT, &format)) {
+ // Resolving GL functions may need a context current, so do it only here.
+ if (!d->gl_egl_image_target_texture_2d)
+ d->gl_egl_image_target_texture_2d = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
+
+ if (!d->gl_egl_image_target_texture_2d) {
+ qWarning("QtCompositor: bindTextureToBuffer() failed. Could not find glEGLImageTargetTexture2DOES.");
+ return;
+ }
+
+ EGLImageKHR image = d->egl_create_image(d->egl_display, EGL_NO_CONTEXT,
+ EGL_WAYLAND_BUFFER_WL,
+ buffer, NULL);
+
+ d->gl_egl_image_target_texture_2d(GL_TEXTURE_2D, image);
+ set_texture_params(GL_TEXTURE_2D);
+ d->egl_destroy_image(d->egl_display, image);
+ } else if (d->egl_query_wayland_buffer(d->egl_display, buffer, EGL_WAYLAND_BUFFER_WL, &streamFd)) {
+ state.egl_stream = d->funcs->create_stream_from_file_descriptor(d->egl_display, streamFd);
+ close(streamFd);
+
+ if (state.egl_stream == EGL_NO_STREAM_KHR) {
+ qWarning("%s:%d: eglCreateStreamFromFileDescriptorKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError());
+ return;
+ }
+
+ state.isYInverted = false;
+ state.gl_texture_target = GL_TEXTURE_EXTERNAL_OES;
+ state.gl_texture = make_texture(state.gl_texture_target);
+ set_texture_params(state.gl_texture_target);
+
+ if (d->funcs->stream_consumer_gltexture(d->egl_display, state.egl_stream) != EGL_TRUE)
+ qWarning("%s:%d: eglStreamConsumerGLTextureExternalKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError());
+ }
+
+ d->buffers[buffer] = state;
}
+}
- EGLImageKHR image = d->egl_create_image(d->egl_display, EGL_NO_CONTEXT,
- EGL_WAYLAND_BUFFER_WL,
- buffer, NULL);
+// Update is only needed for the EGLStream path as that requires calling acquire
+// on every frame. bindTextureToBuffer() is typically invoked only upon attach
+// so that is insufficient.
+void WaylandEglClientBufferIntegration::updateTextureForBuffer(struct ::wl_resource *buffer)
+{
+ Q_D(WaylandEglClientBufferIntegration);
+ if (!d->valid) {
+ qWarning("QtCompositor: updateTextureForBuffer() failed");
+ return;
+ }
- d->gl_egl_image_target_texture_2d(GL_TEXTURE_2D, image);
+ if (!buffer)
+ return;
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ const BufferState state = d->buffers.value(buffer);
- d->egl_destroy_image(d->egl_display, image);
+ if (state.egl_stream != EGL_NO_STREAM_KHR)
+ d->funcs->stream_consumer_acquire(d->egl_display, state.egl_stream);
}
QWaylandSurface::Origin WaylandEglClientBufferIntegration::origin(struct ::wl_resource *buffer) const
{
-#if defined(EGL_WAYLAND_Y_INVERTED_WL)
Q_D(const WaylandEglClientBufferIntegration);
+ if (d->buffers.contains(buffer))
+ return d->buffers[buffer].isYInverted ? QWaylandSurface::OriginTopLeft : QWaylandSurface::OriginBottomLeft;
+
+#if defined(EGL_WAYLAND_Y_INVERTED_WL)
EGLint isYInverted;
EGLBoolean ret = EGL_FALSE;
if (buffer)
ret = d->egl_query_wayland_buffer(d->egl_display, buffer, EGL_WAYLAND_Y_INVERTED_WL, &isYInverted);
-
// Yes, this looks strange, but the specification says that EGL_FALSE return
// value (not supported) should be treated the same as EGL_TRUE return value
// and EGL_TRUE in value.
@@ -220,6 +383,9 @@ void *WaylandEglClientBufferIntegration::lockNativeBuffer(struct ::wl_resource *
{
Q_D(const WaylandEglClientBufferIntegration);
+ if (d->buffers.contains(buffer) && d->buffers[buffer].egl_stream != EGL_NO_STREAM_KHR)
+ return 0;
+
EGLImageKHR image = d->egl_create_image(d->egl_display, EGL_NO_CONTEXT,
EGL_WAYLAND_BUFFER_WL,
buffer, NULL);
@@ -229,8 +395,11 @@ void *WaylandEglClientBufferIntegration::lockNativeBuffer(struct ::wl_resource *
void WaylandEglClientBufferIntegration::unlockNativeBuffer(void *native_buffer) const
{
Q_D(const WaylandEglClientBufferIntegration);
- EGLImageKHR image = static_cast<EGLImageKHR>(native_buffer);
+ if (!native_buffer)
+ return;
+
+ EGLImageKHR image = static_cast<EGLImageKHR>(native_buffer);
d->egl_destroy_image(d->egl_display, image);
}
@@ -238,11 +407,15 @@ QSize WaylandEglClientBufferIntegration::bufferSize(struct ::wl_resource *buffer
{
Q_D(const WaylandEglClientBufferIntegration);
- int width, height;
- d->egl_query_wayland_buffer(d->egl_display, buffer, EGL_WIDTH, &width);
- d->egl_query_wayland_buffer(d->egl_display, buffer, EGL_HEIGHT, &height);
+ if (d->buffers.contains(buffer)) {
+ return d->buffers[buffer].size;
+ } else {
+ int width, height;
+ d->egl_query_wayland_buffer(d->egl_display, buffer, EGL_WIDTH, &width);
+ d->egl_query_wayland_buffer(d->egl_display, buffer, EGL_HEIGHT, &height);
- return QSize(width, height);
+ return QSize(width, height);
+ }
}
QT_END_NAMESPACE