diff options
12 files changed, 165 insertions, 25 deletions
diff --git a/examples/wayland/qwindow-compositor/compositorwindow.cpp b/examples/wayland/qwindow-compositor/compositorwindow.cpp index 7e10a1739..537a3d08a 100644 --- a/examples/wayland/qwindow-compositor/compositorwindow.cpp +++ b/examples/wayland/qwindow-compositor/compositorwindow.cpp @@ -116,10 +116,18 @@ void CompositorWindow::paintGL() functions->glEnable(GL_BLEND); functions->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GLenum currentTarget = GL_TEXTURE_2D; Q_FOREACH (WindowCompositorView *view, m_compositor->views()) { if (view->isCursor()) continue; - GLuint textureId = view->getTexture(); + GLenum target; + GLuint textureId = view->getTexture(&target); + if (!textureId || !target) + continue; + if (target != currentTarget) { + currentTarget = target; + m_textureBlitter.bind(currentTarget); + } QWaylandSurface *surface = view->surface(); if (surface && surface->isMapped()) { QSize s = surface->size(); diff --git a/examples/wayland/qwindow-compositor/windowcompositor.cpp b/examples/wayland/qwindow-compositor/windowcompositor.cpp index bd39908e5..ecbbc5041 100644 --- a/examples/wayland/qwindow-compositor/windowcompositor.cpp +++ b/examples/wayland/qwindow-compositor/windowcompositor.cpp @@ -50,25 +50,42 @@ #include <QtWaylandCompositor/qwaylanddrag.h> #include <QDebug> +#include <QOpenGLContext> + +#ifndef GL_TEXTURE_EXTERNAL_OES +#define GL_TEXTURE_EXTERNAL_OES 0x8D65 +#endif WindowCompositorView::WindowCompositorView() - : m_texture(0) + : m_textureTarget(GL_TEXTURE_2D) + , m_texture(0) , m_wlShellSurface(nullptr) , m_xdgSurface(nullptr) , m_xdgPopup(nullptr) , m_parentView(nullptr) {} -GLuint WindowCompositorView::getTexture() { +GLuint WindowCompositorView::getTexture(GLenum *target) +{ + QWaylandBufferRef buf = currentBuffer(); + m_texture = buf.textureForPlane(0); + + if (buf.bufferFormatEgl() == QWaylandBufferRef::BufferFormatEgl_EXTERNAL_OES) + m_textureTarget = GL_TEXTURE_EXTERNAL_OES; + if (advance()) { - if (m_texture) - glDeleteTextures(1, &m_texture); + if (!m_texture) + glGenTextures(1, &m_texture); - glGenTextures(1, &m_texture); - glBindTexture(GL_TEXTURE_2D, m_texture); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - currentBuffer().bindToTexture(); + glBindTexture(m_textureTarget, m_texture); + buf.bindToTexture(); } + + buf.updateTexture(); + + if (target) + *target = m_textureTarget; + return m_texture; } diff --git a/examples/wayland/qwindow-compositor/windowcompositor.h b/examples/wayland/qwindow-compositor/windowcompositor.h index 5290d7c85..80a7bebe4 100644 --- a/examples/wayland/qwindow-compositor/windowcompositor.h +++ b/examples/wayland/qwindow-compositor/windowcompositor.h @@ -59,7 +59,7 @@ class WindowCompositorView : public QWaylandView Q_OBJECT public: WindowCompositorView(); - GLuint getTexture(); + GLuint getTexture(GLenum *target = 0); QPointF position() const { return m_position; } void setPosition(const QPointF &pos) { m_position = pos; } bool isCursor() const; @@ -72,6 +72,7 @@ public: private: friend class WindowCompositor; + GLenum m_textureTarget; GLuint m_texture; QPointF m_position; QWaylandWlShellSurface *m_wlShellSurface; diff --git a/src/compositor/compositor_api/qwaylandbufferref.cpp b/src/compositor/compositor_api/qwaylandbufferref.cpp index 929503b4f..e9fbcfbdb 100644 --- a/src/compositor/compositor_api/qwaylandbufferref.cpp +++ b/src/compositor/compositor_api/qwaylandbufferref.cpp @@ -241,6 +241,16 @@ QImage QWaylandBufferRef::image() const return d->buffer->image(); } +#ifdef QT_COMPOSITOR_WAYLAND_GL +GLuint QWaylandBufferRef::textureForPlane(int plane) const +{ + if (d->nullOrDestroyed()) + return 0; + + return d->buffer->textureForPlane(plane); +} +#endif + /*! * Binds the buffer to the current OpenGL texture. This may * perform a copy of the buffer data, depending on the platform diff --git a/src/compositor/compositor_api/qwaylandbufferref.h b/src/compositor/compositor_api/qwaylandbufferref.h index 4ded8f17b..50c85b965 100644 --- a/src/compositor/compositor_api/qwaylandbufferref.h +++ b/src/compositor/compositor_api/qwaylandbufferref.h @@ -96,6 +96,9 @@ public: bool isShm() const; QImage image() const; +#ifdef QT_COMPOSITOR_WAYLAND_GL + GLuint textureForPlane(int plane) const; +#endif void bindToTexture() const; void updateTexture() const; diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp index 9fa81cfb2..ab11ff4f8 100644 --- a/src/compositor/compositor_api/qwaylandquickitem.cpp +++ b/src/compositor/compositor_api/qwaylandquickitem.cpp @@ -179,17 +179,6 @@ QWaylandBufferMaterial::QWaylandBufferMaterial(QWaylandBufferRef::BufferFormatEg { QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); - for (int i = 0; i < bufferTypes[m_format].planeCount; i++) { - GLuint texture; - gl->glGenTextures(1, &texture); - gl->glBindTexture(bufferTypes[m_format].textureTarget, texture); - gl->glTexParameteri(bufferTypes[m_format].textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl->glTexParameteri(bufferTypes[m_format].textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl->glTexParameteri(bufferTypes[m_format].textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->glTexParameteri(bufferTypes[m_format].textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - m_textures << texture; - } - gl->glBindTexture(bufferTypes[m_format].textureTarget, 0); setFlag(bufferTypes[m_format].materialFlags); } @@ -202,11 +191,36 @@ QWaylandBufferMaterial::~QWaylandBufferMaterial() gl->glDeleteTextures(1, &texture); } +void QWaylandBufferMaterial::setTextureForPlane(int plane, uint texture) +{ + if (plane < 0 || plane >= bufferTypes[m_format].planeCount) { + qWarning("plane index is out of range"); + return; + } + + QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); + const GLenum target = bufferTypes[m_format].textureTarget; + + gl->glBindTexture(target, texture); + setTextureParameters(target); + + ensureTextures(plane - 1); + + if (m_textures.size() <= plane) { + m_textures << texture; + } else { + std::swap(m_textures[plane], texture); + gl->glDeleteTextures(1, &texture); + } +} + void QWaylandBufferMaterial::bind() { QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); const GLenum target = bufferTypes[m_format].textureTarget; + ensureTextures(bufferTypes[m_format].planeCount); + switch (m_textures.size()) { case 3: gl->glActiveTexture(GL_TEXTURE2); @@ -230,6 +244,31 @@ QSGMaterialShader *QWaylandBufferMaterial::createShader() const return new QWaylandBufferMaterialShader(m_format); } + +void QWaylandBufferMaterial::setTextureParameters(GLenum target) +{ + QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); + gl->glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl->glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl->glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl->glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +//TODO move this into a separate centralized texture management class +void QWaylandBufferMaterial::ensureTextures(int count) +{ + QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); + const GLenum target = bufferTypes[m_format].textureTarget; + GLuint texture; + + for (int plane = m_textures.size(); plane < count; plane++) { + gl->glGenTextures(1, &texture); + gl->glBindTexture(target, texture); + setTextureParameters(target); + m_textures << texture; + } +} + QMutex *QWaylandQuickItemPrivate::mutex = 0; class QWaylandSurfaceTextureProvider : public QSGTextureProvider @@ -1047,6 +1086,9 @@ QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat if (d->newTexture) { d->newTexture = false; + for (int plane = 0; plane < bufferTypes[ref.bufferFormatEgl()].planeCount; plane++) + if (uint texture = ref.textureForPlane(plane)) + material->setTextureForPlane(plane, texture); material->bind(); ref.bindToTexture(); } diff --git a/src/compositor/compositor_api/qwaylandquickitem_p.h b/src/compositor/compositor_api/qwaylandquickitem_p.h index 679d218ee..b529ba959 100644 --- a/src/compositor/compositor_api/qwaylandquickitem_p.h +++ b/src/compositor/compositor_api/qwaylandquickitem_p.h @@ -85,12 +85,17 @@ public: QWaylandBufferMaterial(QWaylandBufferRef::BufferFormatEgl format); ~QWaylandBufferMaterial(); + void setTextureForPlane(int plane, uint texture); + void bind(); QSGMaterialType *type() const Q_DECL_OVERRIDE; QSGMaterialShader *createShader() const Q_DECL_OVERRIDE; private: + void setTextureParameters(GLenum target); + void ensureTextures(int count); + const QWaylandBufferRef::BufferFormatEgl m_format; QVarLengthArray<GLuint, 3> m_textures; }; diff --git a/src/compositor/hardware_integration/qwlclientbufferintegration_p.h b/src/compositor/hardware_integration/qwlclientbufferintegration_p.h index 1fbcb7991..90762437b 100644 --- a/src/compositor/hardware_integration/qwlclientbufferintegration_p.h +++ b/src/compositor/hardware_integration/qwlclientbufferintegration_p.h @@ -73,6 +73,7 @@ public: virtual void initializeBuffer(struct ::wl_resource *buffer) { Q_UNUSED(buffer); } virtual QWaylandBufferRef::BufferFormatEgl bufferFormat(struct ::wl_resource *buffer) { Q_UNUSED(buffer); return QWaylandBufferRef::BufferFormatEgl_RGBA; } + virtual uint textureForBuffer(struct ::wl_resource *buffer, int plane) { Q_UNUSED(buffer); Q_UNUSED(plane); return 0; } virtual void bindTextureToBuffer(struct ::wl_resource *buffer) = 0; virtual void updateTextureForBuffer(struct ::wl_resource *buffer) { Q_UNUSED(buffer); } diff --git a/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp b/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp index c7bdbcee5..14ccde13a 100644 --- a/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp +++ b/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp @@ -232,6 +232,14 @@ void SurfaceBuffer::bindToTexture() const } } +uint SurfaceBuffer::textureForPlane(int plane) const +{ + if (QtWayland::ClientBufferIntegration *clientInt = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration()) + return clientInt->textureForBuffer(m_buffer, plane); + + return 0; +} + void SurfaceBuffer::updateTexture() const { if (QtWayland::ClientBufferIntegration *clientInt = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration()) diff --git a/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h b/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h index 85f78d41b..95e7e8158 100644 --- a/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h +++ b/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h @@ -106,6 +106,7 @@ public: QImage image() const; QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const; void bindToTexture() const; + uint textureForPlane(int plane) const; void updateTexture() const; static bool hasContent(SurfaceBuffer *buffer) { return buffer && buffer->waylandBufferHandle(); } diff --git a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp index e6b68225b..1c009d342 100644 --- a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp +++ b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp @@ -117,6 +117,7 @@ struct BufferState EGLint egl_format; QVarLengthArray<EGLImageKHR, 3> egl_images; EGLStreamKHR egl_stream; + GLuint eglstream_texture; bool isYInverted; QSize size; @@ -167,6 +168,7 @@ struct buffer_destroy_listener : wl_listener BufferState::BufferState() : egl_format(EGL_TEXTURE_RGBA) , egl_stream(EGL_NO_STREAM_KHR) + , eglstream_texture(0) , isYInverted(true) {} @@ -269,7 +271,21 @@ void WaylandEglClientBufferIntegrationPrivate::attach_egl_fd_texture(struct ::wl return; } + if (!QOpenGLContext::currentContext()) + qWarning("EglClientBufferIntegration: creating texture with no current context"); + + //TODO This texture might end up in a different context than the quick item which wants to use it, this needs to be fixed somehow. + glGenTextures(1, &state.eglstream_texture); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, state.eglstream_texture); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + register_buffer(buffer, state); + + bindBuffer(buffer); } void WaylandEglClientBufferIntegrationPrivate::register_buffer(struct ::wl_resource *buffer, BufferState state) @@ -301,8 +317,12 @@ void WaylandEglClientBufferIntegrationPrivate::bindBuffer(struct ::wl_resource * const BufferState state = buffers.value(buffer); if (state.egl_stream != EGL_NO_STREAM_KHR) { - if (funcs->stream_consumer_gltexture(egl_display, state.egl_stream) != EGL_TRUE) - qWarning("%s:%d: eglStreamConsumerGLTextureExternalKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError()); + EGLint stream_state; + funcs->query_stream(egl_display, state.egl_stream, EGL_STREAM_STATE_KHR, &stream_state); + + if (stream_state == EGL_STREAM_STATE_CREATED_KHR) + if (funcs->stream_consumer_gltexture(egl_display, state.egl_stream) != EGL_TRUE) + qWarning("%s:%d: eglStreamConsumerGLTextureExternalKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError()); } else { GLint previousTexture = GL_TEXTURE0; glGetIntegerv(GL_ACTIVE_TEXTURE, &previousTexture); @@ -340,6 +360,11 @@ void WaylandEglClientBufferIntegrationPrivate::handle_buffer_destroy(wl_listener BufferState state = self->buffers.take(buffer); + /* TODO This texture shouldn't get deleted here as the compositor might want to show an transition. But at the same time we need to make sure + that the texture is deleted properly although if the compositor didn't use it (e.g. by creating a quick item)*/ + if (state.eglstream_texture) + glDeleteTextures(1, &state.eglstream_texture); + for (int i = 0; i < state.egl_images.size(); i++) self->egl_destroy_image(self->egl_display, state.egl_images[i]); @@ -453,6 +478,17 @@ QWaylandBufferRef::BufferFormatEgl WaylandEglClientBufferIntegration::bufferForm return formatFromEglFormat(d->buffers.value(buffer).egl_format); } +uint WaylandEglClientBufferIntegration::textureForBuffer(wl_resource *buffer, int plane) +{ + Q_UNUSED(plane) + Q_D(WaylandEglClientBufferIntegration); + if (!buffer) + return 0; + + const BufferState state = d->buffers.value(buffer); + return state.eglstream_texture; +} + void WaylandEglClientBufferIntegration::bindTextureToBuffer(struct ::wl_resource *buffer) { Q_D(WaylandEglClientBufferIntegration); @@ -475,8 +511,15 @@ void WaylandEglClientBufferIntegration::updateTextureForBuffer(struct ::wl_resou const 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); + if (state.egl_stream != EGL_NO_STREAM_KHR) { + EGLint stream_state; + d->funcs->query_stream(d->egl_display, state.egl_stream, EGL_STREAM_STATE_KHR, &stream_state); + + if (stream_state == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) { + if (d->funcs->stream_consumer_acquire(d->egl_display, state.egl_stream) != EGL_TRUE) + qWarning("%s:%d: eglStreamConsumerAcquireKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError()); + } + } } QWaylandSurface::Origin WaylandEglClientBufferIntegration::origin(struct ::wl_resource *buffer) const diff --git a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h index 57e83717a..74cad708d 100644 --- a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h +++ b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h @@ -54,6 +54,7 @@ public: void initializeBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; QWaylandBufferRef::BufferFormatEgl bufferFormat(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; + uint textureForBuffer(struct ::wl_resource *buffer, int plane) Q_DECL_OVERRIDE; void bindTextureToBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; void updateTextureForBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; |