From b33ac5a7d7bff88021fe6b02c0cbf5c64124042e Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 16 Oct 2015 17:07:55 +0200 Subject: Fix for QStringBuilder Change-Id: I2a7b82bd2705919a91492edfccac02f4d8fc2c9b Reviewed-by: Louai Al-Khanji --- src/qtwaylandscanner/qtwaylandscanner.cpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/qtwaylandscanner/qtwaylandscanner.cpp b/src/qtwaylandscanner/qtwaylandscanner.cpp index 784687d26..a9c171543 100644 --- a/src/qtwaylandscanner/qtwaylandscanner.cpp +++ b/src/qtwaylandscanner/qtwaylandscanner.cpp @@ -196,8 +196,13 @@ QByteArray waylandToCType(const QByteArray &waylandType, const QByteArray &inter return "int32_t"; else if (waylandType == "array") return "wl_array *"; - else if (waylandType == "object" || waylandType == "new_id") - return isServerSide() ? "struct ::wl_resource *" : interface.isEmpty() ? "struct ::wl_object *" : "struct ::" + interface + " *"; + else if (waylandType == "object" || waylandType == "new_id") { + if (isServerSide()) + return "struct ::wl_resource *"; + if (interface.isEmpty()) + return "struct ::wl_object *"; + return "struct ::" + interface + " *"; + } return waylandType; } @@ -839,7 +844,14 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr printf("\n"); foreach (const WaylandEvent &e, interface.requests) { const WaylandArgument *new_id = newIdArgument(e.arguments); - printf(" %s", new_id ? (new_id->interface.isEmpty() ? "void *" : "struct ::" + new_id->interface + " *").constData() : "void "); + QByteArray new_id_str = "void "; + if (new_id) { + if (new_id->interface.isEmpty()) + new_id_str = "void *"; + else + new_id_str = "struct ::" + new_id->interface + " *"; + } + printf(" %s", new_id_str.constData()); printEvent(e); printf(";\n"); } @@ -955,7 +967,14 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr printf("\n"); const WaylandEvent &e = interface.requests.at(i); const WaylandArgument *new_id = newIdArgument(e.arguments); - printf(" %s%s::", new_id ? (new_id->interface.isEmpty() ? "void *" : "struct ::" + new_id->interface + " *").constData() : "void ", interfaceName); + QByteArray new_id_str = "void "; + if (new_id) { + if (new_id->interface.isEmpty()) + new_id_str = "void *"; + else + new_id_str = "struct ::" + new_id->interface + " *"; + } + printf(" %s%s::", new_id_str.constData(), interfaceName); printEvent(e); printf("\n"); printf(" {\n"); -- cgit v1.2.3 From 505c37307980e20baf02961d1be5abf858d5510a Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 15 Oct 2015 16:52:33 +0200 Subject: Fix build without pkg-config Change-Id: I9217c633bcbecd330715b6dbc654245b3fb739a8 Reviewed-by: Louai Al-Khanji --- examples/wayland/server-buffer/client/client.pro | 9 +++++++-- examples/wayland/server-buffer/compositor/compositor.pro | 3 --- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/wayland/server-buffer/client/client.pro b/examples/wayland/server-buffer/client/client.pro index ce4a04f91..9d408d9e9 100644 --- a/examples/wayland/server-buffer/client/client.pro +++ b/examples/wayland/server-buffer/client/client.pro @@ -3,8 +3,13 @@ TARGET = client INCLUDEPATH += . QT += waylandclient-private -CONFIG += link_pkgconfig -PKGCONFIG += wayland-client + +!contains(QT_CONFIG, no-pkg-config) { + PKGCONFIG += wayland-client + CONFIG += link_pkgconfig +} else { + LIBS += -lwayland-client +} CONFIG += wayland-scanner WAYLANDCLIENTSOURCES += ../share-buffer.xml diff --git a/examples/wayland/server-buffer/compositor/compositor.pro b/examples/wayland/server-buffer/compositor/compositor.pro index 9f7751a09..8d7f48820 100644 --- a/examples/wayland/server-buffer/compositor/compositor.pro +++ b/examples/wayland/server-buffer/compositor/compositor.pro @@ -17,7 +17,4 @@ RESOURCES += compositor.qrc CONFIG +=wayland-scanner WAYLANDSERVERSOURCES += ../share-buffer.xml -CONFIG += link_pkgconfig -PKGCONFIG += wayland-server - DEFINES += QT_COMPOSITOR_QUICK -- cgit v1.2.3 From 7f646611ca996320fec933633711b9d89833863c Mon Sep 17 00:00:00 2001 From: Olivier Blin Date: Tue, 13 Oct 2015 19:24:37 +0200 Subject: Fix setting focusDestroyListener when no keyboard resource is bound When no keyboard resource is bound, the destruction handler for the focused surface was not called, and the pointers to focused objects were not reset. Thus the m_focus surface pointer could become invalid. Change-Id: Iee404219304ae7b2bae87131ab140ab134e98118 Reviewed-by: Giulio Camuffo --- src/compositor/wayland_wrapper/qwlkeyboard.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/compositor/wayland_wrapper/qwlkeyboard.cpp b/src/compositor/wayland_wrapper/qwlkeyboard.cpp index 3d0af6aaf..7520fae3f 100644 --- a/src/compositor/wayland_wrapper/qwlkeyboard.cpp +++ b/src/compositor/wayland_wrapper/qwlkeyboard.cpp @@ -118,10 +118,15 @@ KeyboardGrabber *Keyboard::currentGrab() const void Keyboard::focused(Surface *surface) { - if (m_focusResource && m_focus != surface) { - uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); - send_leave(m_focusResource->handle, serial, m_focus->resource()->handle); + if (m_focus != surface) { + if (m_focusResource) { + uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); + send_leave(m_focusResource->handle, serial, m_focus->resource()->handle); + } m_focusDestroyListener.reset(); + if (surface) { + m_focusDestroyListener.listenForDestruction(surface->resource()->handle); + } } Resource *resource = surface ? resourceMap().value(surface->resource()->client()) : 0; @@ -130,7 +135,6 @@ void Keyboard::focused(Surface *surface) uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); send_modifiers(resource->handle, serial, m_modsDepressed, m_modsLatched, m_modsLocked, m_group); send_enter(resource->handle, serial, surface->resource()->handle, QByteArray::fromRawData((char *)m_keys.data(), m_keys.size() * sizeof(uint32_t))); - m_focusDestroyListener.listenForDestruction(surface->resource()->handle); } m_focusResource = resource; -- cgit v1.2.3 From 3a584414d9df972721a4fbf4b1088bce5e95484b Mon Sep 17 00:00:00 2001 From: Olivier Blin Date: Mon, 12 Oct 2015 17:27:51 +0200 Subject: Update focusResource if needed when wl_keyboard is bound If a QtWayland compositor gives focus to a surface right after its creation during the client startup, the keyboard resource may not be bound yet by the client. In this case, the surface is correctly marked as focused, but the keyboard resource is never marked as focused, and thus no keys are ever sent to the client. To fix this, the focusResource is updated if needed after wl_keyboard is bound. This can be reproduced with weston-simple-im (patched to use wl_shell instead of xdg_shell) and qml-compositor, modified to enable TextInputExtension and call takeFocus() at the end of windowAdded(). Change-Id: I551cb5bc56c05a1e5187b23108f4ef80468782dc Reviewed-by: Giulio Camuffo --- src/compositor/wayland_wrapper/qwlkeyboard.cpp | 42 +++++++++++++++++++++----- src/compositor/wayland_wrapper/qwlkeyboard_p.h | 3 ++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/compositor/wayland_wrapper/qwlkeyboard.cpp b/src/compositor/wayland_wrapper/qwlkeyboard.cpp index 7520fae3f..7a5ed5f25 100644 --- a/src/compositor/wayland_wrapper/qwlkeyboard.cpp +++ b/src/compositor/wayland_wrapper/qwlkeyboard.cpp @@ -116,6 +116,30 @@ KeyboardGrabber *Keyboard::currentGrab() const return m_grab; } +void Keyboard::checkFocusResource(wl_keyboard::Resource *keyboardResource) +{ + if (!keyboardResource || !m_focus) + return; + + // this is already the current resource, do no send enter twice + if (m_focusResource == keyboardResource) + return; + + // check if new wl_keyboard resource is from the client owning the focus surface + struct ::wl_client *focusedClient = m_focus->resource()->client(); + if (focusedClient == keyboardResource->client()) { + sendEnter(m_focus, keyboardResource); + m_focusResource = keyboardResource; + } +} + +void Keyboard::sendEnter(Surface *surface, wl_keyboard::Resource *keyboardResource) +{ + uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); + send_modifiers(keyboardResource->handle, serial, m_modsDepressed, m_modsLatched, m_modsLocked, m_group); + send_enter(keyboardResource->handle, serial, surface->resource()->handle, QByteArray::fromRawData((char *)m_keys.data(), m_keys.size() * sizeof(uint32_t))); +} + void Keyboard::focused(Surface *surface) { if (m_focus != surface) { @@ -132,9 +156,7 @@ void Keyboard::focused(Surface *surface) Resource *resource = surface ? resourceMap().value(surface->resource()->client()) : 0; if (resource && (m_focus != surface || m_focusResource != resource)) { - uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); - send_modifiers(resource->handle, serial, m_modsDepressed, m_modsLatched, m_modsLocked, m_group); - send_enter(resource->handle, serial, surface->resource()->handle, QByteArray::fromRawData((char *)m_keys.data(), m_keys.size() * sizeof(uint32_t))); + sendEnter(surface, resource); } m_focusResource = resource; @@ -200,13 +222,17 @@ void Keyboard::keyboard_bind_resource(wl_keyboard::Resource *resource) if (m_context) { send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, m_keymap_fd, m_keymap_size); - return; } + else #endif - int null_fd = open("/dev/null", O_RDONLY); - send_keymap(resource->handle, 0 /* WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP */, - null_fd, 0); - close(null_fd); + { + int null_fd = open("/dev/null", O_RDONLY); + send_keymap(resource->handle, 0 /* WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP */, + null_fd, 0); + close(null_fd); + } + + checkFocusResource(resource); } void Keyboard::keyboard_destroy_resource(wl_keyboard::Resource *resource) diff --git a/src/compositor/wayland_wrapper/qwlkeyboard_p.h b/src/compositor/wayland_wrapper/qwlkeyboard_p.h index e47bd2102..15185ed56 100644 --- a/src/compositor/wayland_wrapper/qwlkeyboard_p.h +++ b/src/compositor/wayland_wrapper/qwlkeyboard_p.h @@ -132,6 +132,9 @@ protected: void keyboard_release(Resource *resource) Q_DECL_OVERRIDE; private: + void checkFocusResource(wl_keyboard::Resource *resource); + void sendEnter(Surface *surface, wl_keyboard::Resource *resource); + void sendKeyEvent(uint code, uint32_t state); void focusDestroyed(void *data); -- cgit v1.2.3 From 955ac0d0eeaf2f543676b649291558f4dcce37c3 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 15 Oct 2015 18:26:00 +0200 Subject: Support EGLStream in wayland-egl For Wayland on NVIDIA. Tested with a Jetson TK1 Pro and Vibrante Linux. With just the hw integration no compositors would work out of the box since EGL_KHR_stream_consumer_gltexture only allows connecting to the texture bound to GL_TEXTURE_EXTERNAL_OES, meaning that assumptions about the target always being GL_TEXTURE_2D break horribly both in C++ and in shader code. In addition, buffers have to be extended with an additional updateTexture() operation as EGLStream requires to call ConsumerAcquire on every frame. Previously there was no concept of this as calling createTexture() on attach() was sufficient. Qt Quick bits are omitted since the refactored compositor API is pretty different. This means that QML compositors will not currently function in this environment. The qwindow-compositor example is enhanced to support the external texture target, but this won't apply for the refactored branch either. It is provided for testing purposes for the time being, and to show how C++ compositors can support different texture targets and correct operation with EGLStreams. Done-with: Louai Al-Khanji Change-Id: I0e209fc0cbcf435cca83528d938eb50e4bdceb82 Reviewed-by: Louai Al-Khanji --- .../qwindow-compositor/qwindowcompositor.cpp | 17 +- .../wayland/qwindow-compositor/textureblitter.cpp | 51 +++- .../wayland/qwindow-compositor/textureblitter.h | 6 +- .../compositor_api/qwaylandbufferref.cpp | 12 + src/compositor/compositor_api/qwaylandbufferref.h | 2 + .../qwlclientbufferintegration_p.h | 23 +- .../wayland_wrapper/qwlsurfacebuffer.cpp | 32 ++- .../wayland_wrapper/qwlsurfacebuffer_p.h | 2 + .../waylandeglclientbufferintegration.cpp | 269 ++++++++++++++++++--- .../waylandeglclientbufferintegration.h | 9 +- .../compositor/wayland-egl/wayland-egl.pro | 2 +- 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(surface->bufferAttacher())->texture; + BufferAttacher *ba = static_cast(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 #include #include - #include -#include -#include +#include +#include +#include +#include + +#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(listener); + WaylandEglClientBufferIntegrationPrivate *self = destroy_listener->d; + struct ::wl_resource *buffer = static_cast(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 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(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(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(native_buffer); + if (!native_buffer) + return; + + EGLImageKHR image = static_cast(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 -- cgit v1.2.3 From f242587cbf3ee8ade683414aaa95158a1149db4c Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 27 Oct 2015 12:19:55 +0100 Subject: Make qwindow-compositor build on systems without ext textures Change-Id: I47d7f7d2cb589df8087c23eda60137e7b263f11f Reviewed-by: Andy Nichols --- examples/wayland/qwindow-compositor/textureblitter.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/wayland/qwindow-compositor/textureblitter.cpp b/examples/wayland/qwindow-compositor/textureblitter.cpp index c550985de..df4fa18d8 100644 --- a/examples/wayland/qwindow-compositor/textureblitter.cpp +++ b/examples/wayland/qwindow-compositor/textureblitter.cpp @@ -44,6 +44,10 @@ #include #include +#ifndef GL_TEXTURE_EXTERNAL_OES +#define GL_TEXTURE_EXTERNAL_OES 0x8D65 +#endif + QT_BEGIN_NAMESPACE TextureBlitter::TextureBlitter() -- cgit v1.2.3