diff options
11 files changed, 369 insertions, 56 deletions
diff --git a/examples/wayland/qwindow-compositor/qwindowcompositor.cpp b/examples/wayland/qwindow-compositor/qwindowcompositor.cpp index 5d338692f..4e3f6336b 100644 --- a/examples/wayland/qwindow-compositor/qwindowcompositor.cpp +++ b/examples/wayland/qwindow-compositor/qwindowcompositor.cpp @@ -92,8 +92,10 @@ public: shmTex = new QOpenGLTexture(bufferRef.image(), QOpenGLTexture::DontGenerateMipMaps); shmTex->setWrapMode(QOpenGLTexture::ClampToEdge); texture = shmTex->textureId(); + textureTarget = GL_TEXTURE_2D; } else { texture = bufferRef.createTexture(); + textureTarget = bufferRef.textureTarget(); } } } @@ -112,9 +114,16 @@ public: return bufferRef.image(); } + void updateTexture() + { + if (bufferRef) + bufferRef.updateTexture(); + } + QOpenGLTexture *shmTex; QWaylandBufferRef bufferRef; GLuint texture; + GLenum textureTarget; }; QWindowCompositor::QWindowCompositor(CompositorWindow *window) @@ -326,7 +335,7 @@ void QWindowCompositor::render() if (!m_backgroundTexture) m_backgroundTexture = new QOpenGLTexture(m_backgroundImage, QOpenGLTexture::DontGenerateMipMaps); - m_textureBlitter->bind(); + m_textureBlitter->bind(GL_TEXTURE_2D); // Draw the background image texture m_textureBlitter->drawTexture(m_backgroundTexture->textureId(), QRect(QPoint(0, 0), m_backgroundImage.size()), @@ -336,7 +345,11 @@ void QWindowCompositor::render() foreach (QWaylandSurface *surface, m_surfaces) { if (!surface->visible()) continue; - GLuint texture = static_cast<BufferAttacher *>(surface->bufferAttacher())->texture; + BufferAttacher *ba = static_cast<BufferAttacher *>(surface->bufferAttacher()); + ba->updateTexture(); + const GLuint texture = ba->texture; + const GLenum target = ba->textureTarget; + m_textureBlitter->bind(target); foreach (QWaylandSurfaceView *view, surface->views()) { QRect geo(view->pos().toPoint(),surface->size()); m_textureBlitter->drawTexture(texture,geo,m_window->size(),0,false,surface->isYInverted()); diff --git a/examples/wayland/qwindow-compositor/textureblitter.cpp b/examples/wayland/qwindow-compositor/textureblitter.cpp index a9acfc026..c550985de 100644 --- a/examples/wayland/qwindow-compositor/textureblitter.cpp +++ b/examples/wayland/qwindow-compositor/textureblitter.cpp @@ -48,6 +48,9 @@ QT_BEGIN_NAMESPACE TextureBlitter::TextureBlitter() : m_shaderProgram(new QOpenGLShaderProgram) + , m_shaderProgramExternal(new QOpenGLShaderProgram) + , m_currentProgram(0) + , m_currentTarget(GL_TEXTURE_2D) { static const char *textureVertexProgram = "uniform highp mat4 matrix;\n" @@ -66,33 +69,58 @@ TextureBlitter::TextureBlitter() " gl_FragColor = texture2D(texture, textureCoord);\n" "}\n"; - //Enable transparent windows - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + static const char *textureFragmentProgramExternal = + "#extension GL_OES_EGL_image_external : require\n" + "uniform samplerExternalOES texture;\n" + "varying highp vec2 textureCoord;\n" + "void main() {\n" + " gl_FragColor = texture2D(texture, textureCoord);\n" + "}\n"; m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram); m_shaderProgram->link(); + + m_shaderProgramExternal->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); + m_shaderProgramExternal->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgramExternal); + m_shaderProgramExternal->link(); } TextureBlitter::~TextureBlitter() { delete m_shaderProgram; + delete m_shaderProgramExternal; } -void TextureBlitter::bind() +void TextureBlitter::bind(quint32 target) { + m_currentTarget = target; + switch (target) { + case GL_TEXTURE_2D: + m_currentProgram = m_shaderProgram; + break; + case GL_TEXTURE_EXTERNAL_OES: + m_currentProgram = m_shaderProgramExternal; + break; + default: + qFatal("INVALID TARGET TYPE %d", target); + break; + } - m_shaderProgram->bind(); + m_currentProgram->bind(); m_vertexCoordEntry = m_shaderProgram->attributeLocation("vertexCoordEntry"); m_textureCoordEntry = m_shaderProgram->attributeLocation("textureCoordEntry"); m_matrixLocation = m_shaderProgram->uniformLocation("matrix"); + + //Enable transparent windows + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } void TextureBlitter::release() { - m_shaderProgram->release(); + m_currentProgram->release(); } void TextureBlitter::drawTexture(int textureId, const QRectF &targetRect, const QSize &targetSize, int depth, bool targethasInvertedY, bool sourceHasInvertedY) @@ -148,16 +176,17 @@ void TextureBlitter::drawTexture(int textureId, const QRectF &targetRect, const currentContext->functions()->glVertexAttribPointer(m_vertexCoordEntry, 3, GL_FLOAT, GL_FALSE, 0, vertexCoordinates); currentContext->functions()->glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates); - m_shaderProgram->setUniformValue(m_matrixLocation, m_transformMatrix); - glBindTexture(GL_TEXTURE_2D, textureId); + m_currentProgram->setUniformValue(m_matrixLocation, m_transformMatrix); + + glBindTexture(m_currentTarget, textureId); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(m_currentTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(m_currentTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(m_currentTarget, 0); currentContext->functions()->glDisableVertexAttribArray(m_vertexCoordEntry); currentContext->functions()->glDisableVertexAttribArray(m_textureCoordEntry); diff --git a/examples/wayland/qwindow-compositor/textureblitter.h b/examples/wayland/qwindow-compositor/textureblitter.h index b46d354e0..85e2bbfb4 100644 --- a/examples/wayland/qwindow-compositor/textureblitter.h +++ b/examples/wayland/qwindow-compositor/textureblitter.h @@ -51,7 +51,7 @@ class TextureBlitter public: TextureBlitter(); ~TextureBlitter(); - void bind(); + void bind(quint32 target); void release(); void drawTexture(int textureId, const QRectF &sourceGeometry, const QSize &targetRect, int depth, @@ -59,11 +59,15 @@ public: private: QOpenGLShaderProgram *m_shaderProgram; + QOpenGLShaderProgram *m_shaderProgramExternal; + QOpenGLShaderProgram *m_currentProgram; QMatrix4x4 m_transformMatrix; int m_matrixLocation; int m_vertexCoordEntry; int m_textureCoordEntry; + + quint32 m_currentTarget; }; QT_END_NAMESPACE diff --git a/src/compositor/compositor_api/qwaylandbufferref.cpp b/src/compositor/compositor_api/qwaylandbufferref.cpp index abea24afb..894f50a1c 100644 --- a/src/compositor/compositor_api/qwaylandbufferref.cpp +++ b/src/compositor/compositor_api/qwaylandbufferref.cpp @@ -104,6 +104,12 @@ QImage QWaylandBufferRef::image() const #ifdef QT_COMPOSITOR_WAYLAND_GL +GLenum QWaylandBufferRef::textureTarget() const +{ + Q_ASSERT(d->buffer->textureCreated()); + return d->buffer->textureTarget(); +} + GLuint QWaylandBufferRef::createTexture() { if (!d->buffer->isShmBuffer() && !d->buffer->textureCreated()) { @@ -112,6 +118,12 @@ GLuint QWaylandBufferRef::createTexture() return d->buffer->texture(); } +void QWaylandBufferRef::updateTexture() +{ + if (!d->buffer->isShmBuffer() && d->buffer->textureCreated()) + d->buffer->updateTexture(); +} + void QWaylandBufferRef::destroyTexture() { if (!d->buffer->isShmBuffer() && d->buffer->textureCreated()) { diff --git a/src/compositor/compositor_api/qwaylandbufferref.h b/src/compositor/compositor_api/qwaylandbufferref.h index 103a1b388..0a5f6cd85 100644 --- a/src/compositor/compositor_api/qwaylandbufferref.h +++ b/src/compositor/compositor_api/qwaylandbufferref.h @@ -69,6 +69,8 @@ public: * referring to the same underlying buffer will be destroyed or reset. */ GLuint createTexture(); + GLenum textureTarget() const; + void updateTexture(); void destroyTexture(); void *nativeBuffer() const; #endif diff --git a/src/compositor/hardware_integration/qwlclientbufferintegration_p.h b/src/compositor/hardware_integration/qwlclientbufferintegration_p.h index e4bbb45b9..c19b90309 100644 --- a/src/compositor/hardware_integration/qwlclientbufferintegration_p.h +++ b/src/compositor/hardware_integration/qwlclientbufferintegration_p.h @@ -75,14 +75,29 @@ public: virtual void initializeHardware(QtWayland::Display *waylandDisplay) = 0; - // Used when the hardware integration wants to provide its own texture for a given buffer. - // In most cases the compositor creates and manages the texture so this is not needed. - virtual GLuint textureForBuffer(struct ::wl_resource *buffer) { Q_UNUSED(buffer); return 0; } - virtual void destroyTextureForBuffer(struct ::wl_resource *buffer) { Q_UNUSED(buffer); } + virtual void initialize(struct ::wl_resource *buffer) { Q_UNUSED(buffer); } + + virtual GLenum textureTargetForBuffer(struct ::wl_resource *buffer) const { Q_UNUSED(buffer); return GL_TEXTURE_2D; } + + virtual GLuint textureForBuffer(struct ::wl_resource *buffer) { + Q_UNUSED(buffer); + GLuint texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + return texture; + } + + virtual void destroyTextureForBuffer(struct ::wl_resource *buffer, GLuint texture) + { + Q_UNUSED(buffer); + glDeleteTextures(1, &texture); + } // Called with the texture bound. virtual void bindTextureToBuffer(struct ::wl_resource *buffer) = 0; + virtual void updateTextureForBuffer(struct ::wl_resource *buffer) { Q_UNUSED(buffer); } + virtual bool isYInverted(struct ::wl_resource *) const { return true; } virtual void *lockNativeBuffer(struct ::wl_resource *) const { return 0; } diff --git a/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp b/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp index 066ffd15b..1229d286f 100644 --- a/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp +++ b/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp @@ -99,8 +99,12 @@ void SurfaceBuffer::initialize(struct ::wl_resource *buffer) m_size = QSize(); m_destroy_listener.surfaceBuffer = this; m_destroy_listener.listener.notify = destroy_listener_callback; - if (buffer) + if (buffer) { + ClientBufferIntegration *hwIntegration = m_compositor->clientBufferIntegration(); + hwIntegration->unlockNativeBuffer(m_handle); + hwIntegration->initialize(buffer); wl_signal_add(&buffer->destroy_signal, &m_destroy_listener.listener); + } } void SurfaceBuffer::destructBufferState() @@ -186,12 +190,22 @@ void SurfaceBuffer::destroyTexture() if (hwIntegration->textureForBuffer(m_buffer) == 0) glDeleteTextures(1, &m_texture); else - hwIntegration->destroyTextureForBuffer(m_buffer); + hwIntegration->destroyTextureForBuffer(m_buffer, m_texture); m_texture = 0; } #endif } +uint SurfaceBuffer::textureTarget() const +{ +#ifdef QT_COMPOSITOR_WAYLAND_GL + ClientBufferIntegration *hwIntegration = m_compositor->clientBufferIntegration(); + return hwIntegration->textureTargetForBuffer(m_buffer); +#endif + + return 0; +} + void SurfaceBuffer::handleAboutToBeDisplayed() { qDebug() << Q_FUNC_INFO; @@ -264,17 +278,21 @@ void SurfaceBuffer::createTexture() ClientBufferIntegration *hwIntegration = m_compositor->clientBufferIntegration(); #ifdef QT_COMPOSITOR_WAYLAND_GL - if (!m_texture) - m_texture = hwIntegration->textureForBuffer(m_buffer); - if (!m_texture) - glGenTextures(1, &m_texture); - glBindTexture(GL_TEXTURE_2D, m_texture); + m_texture = hwIntegration->textureForBuffer(m_buffer); hwIntegration->bindTextureToBuffer(m_buffer); #else Q_UNUSED(hwIntegration); #endif } +void SurfaceBuffer::updateTexture() +{ +#ifdef QT_COMPOSITOR_WAYLAND_GL + ClientBufferIntegration *hwIntegration = m_compositor->clientBufferIntegration(); + hwIntegration->updateTextureForBuffer(m_buffer); +#endif +} + bool SurfaceBuffer::isYInverted() const { bool ret = false; diff --git a/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h b/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h index 5d09c5a9f..3401d218b 100644 --- a/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h +++ b/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h @@ -106,6 +106,8 @@ public: bool isDestroyed() { return m_destroyed; } void createTexture(); + uint textureTarget() const; + void updateTexture(); #ifdef QT_COMPOSITOR_WAYLAND_GL inline GLuint texture() const; #else diff --git a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp index 2d5a182c7..e28d2f53e 100644 --- a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp +++ b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp @@ -48,11 +48,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); @@ -74,6 +79,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: @@ -87,10 +114,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; @@ -99,6 +156,8 @@ public: PFNEGLDESTROYIMAGEKHRPROC egl_destroy_image; PFNGLEGLIMAGETARGETTEXTURE2DOESPROC gl_egl_image_target_texture_2d; + + QEGLStreamConvenience *funcs; }; WaylandEglClientBufferIntegration::WaylandEglClientBufferIntegration() @@ -163,51 +222,193 @@ void WaylandEglClientBufferIntegration::initializeHardware(QtWayland::Display *w } } + 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::initialize(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); +} + +GLenum WaylandEglClientBufferIntegration::textureTargetForBuffer(struct ::wl_resource *buffer) const +{ + Q_D(const WaylandEglClientBufferIntegration); + + return d->buffers.value(buffer).gl_texture_target; +} + +GLuint WaylandEglClientBufferIntegration::textureForBuffer(struct ::wl_resource *buffer) +{ + Q_D(WaylandEglClientBufferIntegration); + + if (!buffer) + return 0; + + BufferState state = d->buffers.value(buffer); + + if (state.gl_texture != 0) { + glBindTexture(state.gl_texture_target, state.gl_texture); + return state.gl_texture; + } + + 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)) { + state.gl_texture_target = GL_TEXTURE_2D; + state.gl_texture = make_texture(state.gl_texture_target); + } 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 0; + } + + 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; + return state.gl_texture; +} + +void WaylandEglClientBufferIntegration::destroyTextureForBuffer(struct ::wl_resource *buffer, GLuint texture) { Q_D(WaylandEglClientBufferIntegration); + Q_UNUSED(texture); + if (!buffer || !d->buffers.contains(buffer)) + return; + + BufferState &state = d->buffers[buffer]; + + if (state.egl_stream != EGL_NO_STREAM_KHR) + return; + + if (state.gl_texture != 0) { + glDeleteTextures(1, &state.gl_texture); + state.gl_texture = 0; + } +} + +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; + + 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); + } else { + Q_ASSERT(QOpenGLContext::currentContext()); + + // 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); } +} - 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); } bool WaylandEglClientBufferIntegration::isYInverted(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; + +#if defined(EGL_WAYLAND_Y_INVERTED_WL) EGLint isYInverted; - EGLBoolean ret; + EGLBoolean ret = EGL_FALSE; 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. @@ -224,6 +425,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); @@ -233,8 +437,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); } @@ -242,11 +449,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 diff --git a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h index 5f660e98a..c3f584835 100644 --- a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h +++ b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h @@ -56,7 +56,15 @@ public: void initializeHardware(QtWayland::Display *waylandDisplay) Q_DECL_OVERRIDE; + void initialize(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; + + GLenum textureTargetForBuffer(struct ::wl_resource *buffer) const Q_DECL_OVERRIDE; + + GLuint textureForBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; + void destroyTextureForBuffer(struct ::wl_resource *buffer, GLuint texture) Q_DECL_OVERRIDE; + void bindTextureToBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; + void updateTextureForBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; bool isYInverted(struct ::wl_resource *) const Q_DECL_OVERRIDE; void *lockNativeBuffer(struct ::wl_resource *buffer) const Q_DECL_OVERRIDE; @@ -72,4 +80,3 @@ private: QT_END_NAMESPACE #endif // WAYLANDEGLINTEGRATION_H - diff --git a/src/plugins/hardwareintegration/compositor/wayland-egl/wayland-egl.pro b/src/plugins/hardwareintegration/compositor/wayland-egl/wayland-egl.pro index 98977591d..c1a23cd64 100644 --- a/src/plugins/hardwareintegration/compositor/wayland-egl/wayland-egl.pro +++ b/src/plugins/hardwareintegration/compositor/wayland-egl/wayland-egl.pro @@ -1,7 +1,7 @@ PLUGIN_TYPE = wayland-graphics-integration-server load(qt_plugin) -QT = compositor compositor-private core-private gui-private +QT = compositor compositor-private core-private gui-private platformsupport-private OTHER_FILES += wayland-egl.json |