diff options
Diffstat (limited to 'src/hardwareintegration')
8 files changed, 368 insertions, 269 deletions
diff --git a/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.cpp b/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.cpp index 508e88257..940ce82f5 100644 --- a/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.cpp +++ b/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.cpp @@ -40,6 +40,7 @@ #include <qpa/qplatformnativeinterface.h> #include <QtGui/QGuiApplication> #include <QtGui/QOpenGLContext> +#include <QOpenGLTexture> #include <qpa/qplatformscreen.h> #include <QtGui/QWindow> @@ -60,6 +61,9 @@ public: : egl_display(EGL_NO_DISPLAY) , valid(false) { } + + static BrcmEglIntegrationPrivate *get(BrcmEglIntegration *integration); + EGLDisplay egl_display; bool valid; PFNEGLQUERYGLOBALIMAGEBRCMPROC eglQueryGlobalImageBRCM; @@ -117,25 +121,46 @@ void BrcmEglIntegration::initializeHardware(struct ::wl_display *display) } } -void BrcmEglIntegration::bindTextureToBuffer(struct ::wl_resource *buffer) +QtWayland::ClientBuffer *BrcmEglIntegration::createBufferFor(wl_resource *buffer) { - Q_D(BrcmEglIntegration); + if (wl_shm_buffer_get(buffer)) + return nullptr; + return new BrcmEglClientBuffer(this, buffer); +} + +BrcmEglIntegrationPrivate *BrcmEglIntegrationPrivate::get(BrcmEglIntegration *integration) +{ + return integration->d_ptr.data(); +} + +QOpenGLTexture *BrcmEglClientBuffer::toOpenGlTexture(int plane) +{ + Q_UNUSED(plane); + + auto d = BrcmEglIntegrationPrivate::get(m_integration); if (!d->valid) { qWarning("bindTextureToBuffer failed!"); - return; + return nullptr; } - BrcmBuffer *brcmBuffer = BrcmBuffer::fromResource(buffer); + BrcmBuffer *brcmBuffer = BrcmBuffer::fromResource(m_buffer); if (!d->eglQueryGlobalImageBRCM(brcmBuffer->handle(), brcmBuffer->handle() + 2)) { qWarning("eglQueryGlobalImageBRCM failed!"); - return; + return nullptr; } EGLImageKHR image = d->eglCreateImageKHR(d->egl_display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer)brcmBuffer->handle(), NULL); if (image == EGL_NO_IMAGE_KHR) qWarning("eglCreateImageKHR() failed: %x\n", eglGetError()); + if (!m_texture) { + m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D); + m_texture->create(); + } + + m_texture->bind(); + d->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -144,6 +169,8 @@ void BrcmEglIntegration::bindTextureToBuffer(struct ::wl_resource *buffer) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); d->eglDestroyImageKHR(d->egl_display, image); + + return m_texture; } void BrcmEglIntegration::brcm_bind_resource(Resource *) @@ -155,11 +182,29 @@ void BrcmEglIntegration::brcm_create_buffer(Resource *resource, uint32_t id, int new BrcmBuffer(resource->client(), id, QSize(width, height), static_cast<EGLint *>(data->data), data->size / sizeof(EGLint)); } -QSize BrcmEglIntegration::bufferSize(struct ::wl_resource *buffer) const +BrcmEglClientBuffer::BrcmEglClientBuffer(BrcmEglIntegration *integration, wl_resource *buffer) + : ClientBuffer(buffer) + , m_integration(integration) + , m_texture(nullptr) +{ +} + +QWaylandBufferRef::BufferFormatEgl BrcmEglClientBuffer::bufferFormatEgl() const { - BrcmBuffer *brcmBuffer = BrcmBuffer::fromResource(buffer); + return QWaylandBufferRef::BufferFormatEgl_RGBA; +} +QSize BrcmEglClientBuffer::size() const +{ + BrcmBuffer *brcmBuffer = BrcmBuffer::fromResource(m_buffer); return brcmBuffer->size(); } +QWaylandSurface::Origin BrcmEglClientBuffer::origin() const +{ + BrcmBuffer *brcmBuffer = BrcmBuffer::fromResource(m_buffer); + return brcmBuffer->isYInverted() ? QWaylandSurface::OriginTopLeft : QWaylandSurface::OriginBottomLeft; +} + + QT_END_NAMESPACE diff --git a/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.h b/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.h index 48dd9c42e..a1d39e4fe 100644 --- a/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.h +++ b/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.h @@ -42,6 +42,8 @@ #include <QtCore/QScopedPointer> +#include <private/qwlclientbuffer_p.h> + QT_BEGIN_NAMESPACE class BrcmEglIntegrationPrivate; @@ -53,10 +55,7 @@ public: BrcmEglIntegration(); void initializeHardware(struct ::wl_display *display) Q_DECL_OVERRIDE; - - void bindTextureToBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; - - QSize bufferSize(struct ::wl_resource *buffer) const Q_DECL_OVERRIDE; + QtWayland::ClientBuffer *createBufferFor(wl_resource *buffer) Q_DECL_OVERRIDE; protected: void brcm_bind_resource(Resource *resource) Q_DECL_OVERRIDE; @@ -67,6 +66,21 @@ private: QScopedPointer<BrcmEglIntegrationPrivate> d_ptr; }; +class BrcmEglClientBuffer : public QtWayland::ClientBuffer +{ +public: + BrcmEglClientBuffer(BrcmEglIntegration *integration, wl_resource *buffer); + + QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const Q_DECL_OVERRIDE; + QSize size() const Q_DECL_OVERRIDE; + QWaylandSurface::Origin origin() const Q_DECL_OVERRIDE; + QOpenGLTexture *toOpenGlTexture(int plane) Q_DECL_OVERRIDE; +private: + BrcmEglIntegration *m_integration; + QOpenGLTexture *m_texture; +}; + + QT_END_NAMESPACE #endif // BRCMEGLINTEGRATION_H diff --git a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp index 4416d103c..d71fce6ae 100644 --- a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp +++ b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp @@ -40,6 +40,7 @@ #include <qpa/qplatformnativeinterface.h> #include <QtGui/QGuiApplication> #include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLTexture> #include <qpa/qplatformscreen.h> #include <QtGui/QWindow> #include <QtCore/QPointer> @@ -90,6 +91,10 @@ #define EGL_TEXTURE_Y_XUXV_WL 0x31D9 #endif +#ifndef EGL_PLATFORM_X11_KHR +#define EGL_PLATFORM_X11_KHR 0x31D5 +#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); @@ -110,17 +115,50 @@ typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenu QT_BEGIN_NAMESPACE +static const char * +egl_error_string(EGLint code) +{ +#define MYERRCODE(x) case x: return #x; + switch (code) { + MYERRCODE(EGL_SUCCESS) + MYERRCODE(EGL_NOT_INITIALIZED) + MYERRCODE(EGL_BAD_ACCESS) + MYERRCODE(EGL_BAD_ALLOC) + MYERRCODE(EGL_BAD_ATTRIBUTE) + MYERRCODE(EGL_BAD_CONTEXT) + MYERRCODE(EGL_BAD_CONFIG) + MYERRCODE(EGL_BAD_CURRENT_SURFACE) + MYERRCODE(EGL_BAD_DISPLAY) + MYERRCODE(EGL_BAD_SURFACE) + MYERRCODE(EGL_BAD_MATCH) + MYERRCODE(EGL_BAD_PARAMETER) + MYERRCODE(EGL_BAD_NATIVE_PIXMAP) + MYERRCODE(EGL_BAD_NATIVE_WINDOW) + MYERRCODE(EGL_CONTEXT_LOST) + default: + return "unknown"; + } +#undef MYERRCODE +} + struct BufferState { BufferState(); + enum EglMode { + ModeNone, + ModeEGLImage, + ModeEGLStream + }; + EGLint egl_format; QVarLengthArray<EGLImageKHR, 3> egl_images; + QOpenGLTexture *textures[3]; EGLStreamKHR egl_stream; - GLuint eglstream_texture; bool isYInverted; QSize size; + EglMode eglMode; }; class WaylandEglClientBufferIntegrationPrivate @@ -128,18 +166,14 @@ class WaylandEglClientBufferIntegrationPrivate public: WaylandEglClientBufferIntegrationPrivate(); - void attach(struct ::wl_resource *buffer); - void attach_egl_texture(struct ::wl_resource *buffer, EGLint format); - void attach_egl_fd_texture(struct ::wl_resource *buffer, EGLNativeFileDescriptorKHR streamFd); + void initBuffer(WaylandEglClientBuffer *buffer); + void init_egl_texture(WaylandEglClientBuffer *buffer, EGLint format); + void init_egl_fd_texture(WaylandEglClientBuffer *buffer, EGLNativeFileDescriptorKHR streamFd); void register_buffer(struct ::wl_resource *buffer, BufferState state); - void bindBuffer(struct ::wl_resource *buffer); - - static void handle_buffer_destroy(wl_listener *listener, void *data); EGLDisplay egl_display; bool valid; bool display_bound; - QHash<struct ::wl_resource *, BufferState> buffers; PFNEGLBINDWAYLANDDISPLAYWL egl_bind_wayland_display; PFNEGLUNBINDWAYLANDDISPLAYWL egl_unbind_wayland_display; @@ -151,25 +185,16 @@ public: PFNGLEGLIMAGETARGETTEXTURE2DOESPROC gl_egl_image_target_texture_2d; QEGLStreamConvenience *funcs; -}; - -struct buffer_destroy_listener : wl_listener -{ - buffer_destroy_listener() - : d(0) - { - notify = WaylandEglClientBufferIntegrationPrivate::handle_buffer_destroy; - wl_list_init(&this->link); + static WaylandEglClientBufferIntegrationPrivate *get(WaylandEglClientBufferIntegration *integration) { + return integration->d_ptr.data(); } - - WaylandEglClientBufferIntegrationPrivate *d; }; BufferState::BufferState() : egl_format(EGL_TEXTURE_RGBA) , egl_stream(EGL_NO_STREAM_KHR) - , eglstream_texture(0) , isYInverted(true) + , eglMode(ModeNone) {} WaylandEglClientBufferIntegrationPrivate::WaylandEglClientBufferIntegrationPrivate() @@ -183,21 +208,21 @@ WaylandEglClientBufferIntegrationPrivate::WaylandEglClientBufferIntegrationPriva , egl_destroy_image(0) , gl_egl_image_target_texture_2d(0) , funcs(Q_NULLPTR) -{} +{ +} -void WaylandEglClientBufferIntegrationPrivate::attach(struct ::wl_resource *buffer) +void WaylandEglClientBufferIntegrationPrivate::initBuffer(WaylandEglClientBuffer *buffer) { EGLint format; - EGLNativeFileDescriptorKHR streamFd = EGL_NO_FILE_DESCRIPTOR_KHR; - if (egl_query_wayland_buffer(egl_display, buffer, EGL_TEXTURE_FORMAT, &format)) - attach_egl_texture(buffer, format); - else if (egl_query_wayland_buffer(egl_display, buffer, EGL_WAYLAND_BUFFER_WL, &streamFd)) - attach_egl_fd_texture(buffer, streamFd); + if (egl_query_wayland_buffer(egl_display, buffer->waylandBufferHandle(), EGL_TEXTURE_FORMAT, &format)) + init_egl_texture(buffer, format); } -void WaylandEglClientBufferIntegrationPrivate::attach_egl_texture(struct ::wl_resource *buffer, EGLint format) +void WaylandEglClientBufferIntegrationPrivate::init_egl_texture(WaylandEglClientBuffer *buffer, EGLint format) { +// Non-streaming case + // Resolving GL functions may need a context current, so do it only here. if (!gl_egl_image_target_texture_2d) gl_egl_image_target_texture_2d = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES")); @@ -207,12 +232,13 @@ void WaylandEglClientBufferIntegrationPrivate::attach_egl_texture(struct ::wl_re return; } - BufferState state; + BufferState &state = *buffer->d; state.egl_format = format; + state.eglMode = BufferState::ModeEGLImage; #if defined(EGL_WAYLAND_Y_INVERTED_WL) EGLint isYInverted; - EGLBoolean ret = egl_query_wayland_buffer(egl_display, buffer, EGL_WAYLAND_Y_INVERTED_WL, &isYInverted); + EGLBoolean ret = egl_query_wayland_buffer(egl_display, buffer->waylandBufferHandle(), 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. @@ -244,21 +270,21 @@ void WaylandEglClientBufferIntegrationPrivate::attach_egl_texture(struct ::wl_re EGLImageKHR image = egl_create_image(egl_display, EGL_NO_CONTEXT, EGL_WAYLAND_BUFFER_WL, - buffer, + buffer->waylandBufferHandle(), attribs); if (image == EGL_NO_IMAGE_KHR) qWarning("failed to create EGL image for plane %d", i); state.egl_images << image; + state.textures[i] = nullptr; } - - register_buffer(buffer, state); } -void WaylandEglClientBufferIntegrationPrivate::attach_egl_fd_texture(struct ::wl_resource *buffer, EGLNativeFileDescriptorKHR streamFd) +void WaylandEglClientBufferIntegrationPrivate::init_egl_fd_texture(WaylandEglClientBuffer *buffer, EGLNativeFileDescriptorKHR streamFd) { - BufferState state; +//EglStreams case + BufferState &state = *buffer->d; state.egl_format = EGL_TEXTURE_EXTERNAL_WL; state.isYInverted = false; @@ -270,106 +296,37 @@ void WaylandEglClientBufferIntegrationPrivate::attach_egl_fd_texture(struct ::wl qWarning("%s:%d: eglCreateStreamFromFileDescriptorKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError()); return; } + state.eglMode = BufferState::ModeEGLStream; 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); + + auto texture = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(GL_TEXTURE_EXTERNAL_OES)); + texture->create(); + state.textures[0] = texture; // TODO: support multiple planes for the streaming case + glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_EXTERNAL_OES, state.eglstream_texture); + texture->create(); + texture->bind(); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture->textureId()); + 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) -{ - Q_ASSERT(!buffers.contains(buffer)); - - EGLint width, height; - egl_query_wayland_buffer(egl_display, buffer, EGL_WIDTH, &width); - egl_query_wayland_buffer(egl_display, buffer, EGL_HEIGHT, &height); - state.size = QSize(width, height); - - buffers[buffer] = state; - - buffer_destroy_listener *destroy_listener = new buffer_destroy_listener; - destroy_listener->d = this; - wl_signal_add(&buffer->destroy_signal, destroy_listener); -} - -void WaylandEglClientBufferIntegrationPrivate::bindBuffer(struct ::wl_resource *buffer) -{ - if (!valid) { - qWarning("QtCompositor: bindTextureToBuffer() failed"); - return; - } + auto newStream = funcs->stream_consumer_gltexture(egl_display, state.egl_stream); - if (!buffer || !buffers.contains(buffer)) - return; - - const BufferState state = buffers.value(buffer); - - if (state.egl_stream != EGL_NO_STREAM_KHR) { - 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); - - const GLenum target = (state.egl_format == EGL_TEXTURE_EXTERNAL_WL) ? GL_TEXTURE_EXTERNAL_OES - : GL_TEXTURE_2D; - - for (int i = 0; i < state.egl_images.size(); i++) { - glActiveTexture(GL_TEXTURE0 + i); - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - gl_egl_image_target_texture_2d(target, state.egl_images[i]); - } - - glActiveTexture(previousTexture); + if (!newStream) { + EGLint code = eglGetError(); + qWarning() << "Could not initialize EGLStream:" << egl_error_string(code) << hex << (long)code; + funcs->destroy_stream(egl_display, state.egl_stream); + state.egl_stream = EGL_NO_STREAM_KHR; } } -void WaylandEglClientBufferIntegrationPrivate::handle_buffer_destroy(wl_listener *listener, void *data) -{ - buffer_destroy_listener *destroy_listener = static_cast<buffer_destroy_listener *>(listener); - WaylandEglClientBufferIntegrationPrivate *self = destroy_listener->d; - struct ::wl_resource *buffer = static_cast<struct ::wl_resource *>(data); - - wl_list_remove(&destroy_listener->link); - delete destroy_listener; - - if (!self->buffers.contains(buffer)) - return; - - Q_ASSERT(self); - Q_ASSERT(buffer); - - BufferState state = self->buffers.take(buffer); - - // We would need to delete the texture of the egl_stream here, but we can't as this breaks the - // texture of the new stream when the window is resized. It seems wayland takes care to delete the texture for us. - - for (int i = 0; i < state.egl_images.size(); i++) - self->egl_destroy_image(self->egl_display, state.egl_images[i]); - - if (state.egl_stream != EGL_NO_STREAM_KHR) - self->funcs->destroy_stream(self->egl_display, state.egl_stream); -} - WaylandEglClientBufferIntegration::WaylandEglClientBufferIntegration() : QtWayland::ClientBufferIntegration() , d_ptr(new WaylandEglClientBufferIntegrationPrivate) @@ -438,17 +395,27 @@ void WaylandEglClientBufferIntegration::initializeHardware(struct wl_display *di d->valid = true; } -void WaylandEglClientBufferIntegration::initializeBuffer(struct ::wl_resource *buffer) +QtWayland::ClientBuffer *WaylandEglClientBufferIntegration::createBufferFor(wl_resource *buffer) { - Q_D(WaylandEglClientBufferIntegration); - if (wl_shm_buffer_get(buffer)) - return; - - if (!buffer || d->buffers.contains(buffer)) - return; + return nullptr; + return new WaylandEglClientBuffer(this, buffer); +} - d->attach(buffer); +WaylandEglClientBuffer::WaylandEglClientBuffer(WaylandEglClientBufferIntegration *integration, wl_resource *buffer) + : ClientBuffer(buffer) + , m_integration(integration) +{ + auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration); + d = new BufferState; + if (buffer && !wl_shm_buffer_get(buffer)) { + EGLint width, height; + p->egl_query_wayland_buffer(p->egl_display, buffer, EGL_WIDTH, &width); + p->egl_query_wayland_buffer(p->egl_display, buffer, EGL_HEIGHT, &height); + d->size = QSize(width, height); + + p->initBuffer(this); + } } static QWaylandBufferRef::BufferFormatEgl formatFromEglFormat(EGLint format) { @@ -470,117 +437,92 @@ static QWaylandBufferRef::BufferFormatEgl formatFromEglFormat(EGLint format) { return QWaylandBufferRef::BufferFormatEgl_RGBA; } -QWaylandBufferRef::BufferFormatEgl WaylandEglClientBufferIntegration::bufferFormat(wl_resource *buffer) -{ - Q_D(const WaylandEglClientBufferIntegration); - return formatFromEglFormat(d->buffers.value(buffer).egl_format); -} - -uint WaylandEglClientBufferIntegration::textureForBuffer(wl_resource *buffer, int plane) +QWaylandBufferRef::BufferFormatEgl WaylandEglClientBuffer::bufferFormatEgl() const { - Q_UNUSED(plane) - Q_D(WaylandEglClientBufferIntegration); - if (!buffer) - return 0; - - const BufferState state = d->buffers.value(buffer); - return state.eglstream_texture; + return formatFromEglFormat(d->egl_format); } -void WaylandEglClientBufferIntegration::bindTextureToBuffer(struct ::wl_resource *buffer) +QOpenGLTexture *WaylandEglClientBuffer::toOpenGlTexture(int plane) { - Q_D(WaylandEglClientBufferIntegration); - d->bindBuffer(buffer); -} - -// 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; + if (!m_buffer) + return nullptr; + + auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration); + auto texture = d->textures[plane]; + const auto target = static_cast<QOpenGLTexture::Target>((d->eglMode == BufferState::ModeEGLStream || d->egl_format == EGL_TEXTURE_EXTERNAL_WL) ? GL_TEXTURE_EXTERNAL_OES + : GL_TEXTURE_2D); + if (!texture) { + texture = new QOpenGLTexture(target); + texture->create(); + d->textures[plane] = texture; } - if (!buffer) - return; - const BufferState state = d->buffers.value(buffer); + if (d->eglMode == BufferState::ModeEGLStream) { + // EGLStream requires calling acquire on every frame. + if (d->egl_stream != EGL_NO_STREAM_KHR) { + + texture->bind(); - 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); + EGLint stream_state; + p->funcs->query_stream(p->egl_display, d->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()); + if (stream_state == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) { + if (p->funcs->stream_consumer_acquire(p->egl_display, d->egl_stream) != EGL_TRUE) + qWarning("%s:%d: eglStreamConsumerAcquireKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError()); + } } + } else if (m_textureDirty) { + texture->bind(); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + p->gl_egl_image_target_texture_2d(target, d->egl_images[plane]); } + return texture; } -QWaylandSurface::Origin WaylandEglClientBufferIntegration::origin(struct ::wl_resource *buffer) const +void WaylandEglClientBuffer::setCommitted(QRegion &damage) { - 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. - if (ret == EGL_FALSE || isYInverted == EGL_TRUE) - return QWaylandSurface::OriginTopLeft; - return QWaylandSurface::OriginBottomLeft; -#endif - - return QtWayland::ClientBufferIntegration::origin(buffer); + ClientBuffer::setCommitted(damage); + if (d->eglMode == BufferState::ModeNone) { + EGLNativeFileDescriptorKHR streamFd = EGL_NO_FILE_DESCRIPTOR_KHR; + auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration); + if (p->egl_query_wayland_buffer(p->egl_display, waylandBufferHandle(), EGL_WAYLAND_BUFFER_WL, &streamFd)) + p->init_egl_fd_texture(this, streamFd); + } } +QWaylandSurface::Origin WaylandEglClientBuffer::origin() const +{ + return d->isYInverted ? QWaylandSurface::OriginTopLeft : QWaylandSurface::OriginBottomLeft; +} -void *WaylandEglClientBufferIntegration::lockNativeBuffer(struct ::wl_resource *buffer) const +void *WaylandEglClientBuffer::lockNativeBuffer() { - Q_D(const WaylandEglClientBufferIntegration); + auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration); - if (d->buffers.contains(buffer) && d->buffers[buffer].egl_stream != EGL_NO_STREAM_KHR) - return 0; + if (d->egl_stream != EGL_NO_STREAM_KHR) + return nullptr; - EGLImageKHR image = d->egl_create_image(d->egl_display, EGL_NO_CONTEXT, + EGLImageKHR image = p->egl_create_image(p->egl_display, EGL_NO_CONTEXT, EGL_WAYLAND_BUFFER_WL, - buffer, NULL); + m_buffer, NULL); return image; } -void WaylandEglClientBufferIntegration::unlockNativeBuffer(void *native_buffer) const +void WaylandEglClientBuffer::unlockNativeBuffer(void *native_buffer) const { - Q_D(const WaylandEglClientBufferIntegration); - if (!native_buffer) return; + auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration); + EGLImageKHR image = static_cast<EGLImageKHR>(native_buffer); - d->egl_destroy_image(d->egl_display, image); + p->egl_destroy_image(p->egl_display, image); } -QSize WaylandEglClientBufferIntegration::bufferSize(struct ::wl_resource *buffer) const +QSize WaylandEglClientBuffer::size() const { - Q_D(const WaylandEglClientBufferIntegration); - - 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 d->size; } QT_END_NAMESPACE diff --git a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h index 74cad708d..5385ac25f 100644 --- a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h +++ b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h @@ -39,6 +39,7 @@ #include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h> #include <QtCore/QScopedPointer> +#include <QtWaylandCompositor/private/qwlclientbuffer_p.h> QT_BEGIN_NAMESPACE @@ -52,22 +53,34 @@ public: void initializeHardware(struct ::wl_display *display) Q_DECL_OVERRIDE; - 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; + QtWayland::ClientBuffer *createBufferFor(wl_resource *buffer); - QWaylandSurface::Origin origin(struct ::wl_resource *) const Q_DECL_OVERRIDE; +private: + Q_DISABLE_COPY(WaylandEglClientBufferIntegration) + QScopedPointer<WaylandEglClientBufferIntegrationPrivate> d_ptr; +}; - void *lockNativeBuffer(struct ::wl_resource *buffer) const Q_DECL_OVERRIDE; - void unlockNativeBuffer(void *native_buffer) const Q_DECL_OVERRIDE; +struct BufferState; - QSize bufferSize(struct ::wl_resource *buffer) const Q_DECL_OVERRIDE; +class WaylandEglClientBuffer : public QtWayland::ClientBuffer +{ +public: + QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const Q_DECL_OVERRIDE; + QSize size() const Q_DECL_OVERRIDE; + QWaylandSurface::Origin origin() const Q_DECL_OVERRIDE; + void *lockNativeBuffer() Q_DECL_OVERRIDE; + void unlockNativeBuffer(void *native_buffer) const Q_DECL_OVERRIDE; + QOpenGLTexture *toOpenGlTexture(int plane) Q_DECL_OVERRIDE; + void setCommitted(QRegion &damage) Q_DECL_OVERRIDE; private: - Q_DISABLE_COPY(WaylandEglClientBufferIntegration) - QScopedPointer<WaylandEglClientBufferIntegrationPrivate> d_ptr; + friend class WaylandEglClientBufferIntegration; + friend class WaylandEglClientBufferIntegrationPrivate; + + WaylandEglClientBuffer(WaylandEglClientBufferIntegration* integration, wl_resource *bufferResource); + + BufferState *d; + WaylandEglClientBufferIntegration *m_integration; }; QT_END_NAMESPACE diff --git a/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.cpp b/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.cpp index e858a8e78..1a478052b 100644 --- a/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.cpp +++ b/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.cpp @@ -40,6 +40,7 @@ #include <QtWaylandCompositor/QWaylandCompositor> #include <QtGui/QGuiApplication> +#include <QtGui/QOpenGLTexture> #include <qpa/qplatformnativeinterface.h> #include <qpa/qplatformopenglcontext.h> @@ -83,23 +84,38 @@ void XCompositeEglClientBufferIntegration::initializeHardware(struct ::wl_displa } else { qFatal("Platform integration doesn't have native interface"); } - mScreen = XDefaultScreen(mDisplay); new XCompositeHandler(m_compositor, mDisplay); } -void XCompositeEglClientBufferIntegration::bindTextureToBuffer(struct ::wl_resource *buffer) +QtWayland::ClientBuffer *XCompositeEglClientBufferIntegration::createBufferFor(wl_resource *buffer) { - XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(buffer); - Pixmap pixmap = XCompositeNameWindowPixmap(mDisplay, compositorBuffer->window()); + if (wl_shm_buffer_get(buffer)) + return nullptr; + return new XCompositeEglClientBuffer(this, buffer); +} + + +XCompositeEglClientBuffer::XCompositeEglClientBuffer(XCompositeEglClientBufferIntegration *integration, wl_resource *bufferResource) + : QtWayland::ClientBuffer(bufferResource) + , m_texture(nullptr) + , m_integration(integration) +{ +} + +QOpenGLTexture *XCompositeEglClientBuffer::toOpenGlTexture(int plane) +{ + Q_UNUSED(plane); + XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(m_buffer); + Pixmap pixmap = XCompositeNameWindowPixmap(m_integration->xDisplay(), compositorBuffer->window()); QVector<EGLint> eglConfigSpec = eglbuildSpec(); EGLint matching = 0; EGLConfig config; - bool matched = eglChooseConfig(mEglDisplay,eglConfigSpec.constData(),&config,1,&matching); + bool matched = eglChooseConfig(m_integration->eglDisplay(),eglConfigSpec.constData(),&config,1,&matching); if (!matched || !matching) { qWarning("Could not retrieve a suitable EGL config"); - return; + return nullptr; } QVector<EGLint> attribList; @@ -110,29 +126,37 @@ void XCompositeEglClientBufferIntegration::bindTextureToBuffer(struct ::wl_resou attribList.append(EGL_TEXTURE_2D); attribList.append(EGL_NONE); - EGLSurface surface = eglCreatePixmapSurface(mEglDisplay,config,pixmap,attribList.constData()); + EGLSurface surface = eglCreatePixmapSurface(m_integration->eglDisplay(),config,pixmap,attribList.constData()); if (surface == EGL_NO_SURFACE) { qDebug() << "Failed to create eglsurface" << pixmap << compositorBuffer->window(); } compositorBuffer->setOrigin(QWaylandSurface::OriginTopLeft); - if (!eglBindTexImage(mEglDisplay,surface,EGL_BACK_BUFFER)) { - qDebug() << "Failed to bind"; + if (!m_texture) { + m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D); + m_texture->create(); + } + m_texture->bind(); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + if (!eglBindTexImage(m_integration->eglDisplay(),surface,EGL_BACK_BUFFER)) { + qWarning() << "Failed to bind"; } // eglDestroySurface(mEglDisplay,surface); + return m_texture; } -QWaylandSurface::Origin XCompositeEglClientBufferIntegration::origin(struct ::wl_resource *buffer) const + +QWaylandSurface::Origin XCompositeEglClientBuffer::origin() const { - XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(buffer); + XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(m_buffer); return compositorBuffer->origin(); } -QSize XCompositeEglClientBufferIntegration::bufferSize(struct ::wl_resource *buffer) const +QSize XCompositeEglClientBuffer::size() const { - XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(buffer); + XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(m_buffer); return compositorBuffer->size(); } diff --git a/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.h b/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.h index c14e582ed..ec4ea284b 100644 --- a/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.h +++ b/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.h @@ -40,7 +40,7 @@ #include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h> #include <QtWaylandCompositor/QWaylandCompositor> - +#include <QtWaylandCompositor/private/qwlclientbuffer_p.h> #include "xlibinclude.h" #include <EGL/egl.h> @@ -53,16 +53,30 @@ public: XCompositeEglClientBufferIntegration(); void initializeHardware(struct ::wl_display *display) Q_DECL_OVERRIDE; - - void bindTextureToBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; - QWaylandSurface::Origin origin(struct ::wl_resource *) const Q_DECL_OVERRIDE; - - QSize bufferSize(struct ::wl_resource *buffer) const Q_DECL_OVERRIDE; + QtWayland::ClientBuffer *createBufferFor(wl_resource *buffer) Q_DECL_OVERRIDE; + inline Display *xDisplay() const { return mDisplay; } + inline EGLDisplay eglDisplay() const { return mEglDisplay; } private: Display *mDisplay; EGLDisplay mEglDisplay; - int mScreen; +}; + +class XCompositeEglClientBuffer : public QtWayland::ClientBuffer +{ +public: + XCompositeEglClientBuffer(XCompositeEglClientBufferIntegration *integration, wl_resource *bufferResource); + + QSize size() const; + QWaylandSurface::Origin origin() const; + QOpenGLTexture *toOpenGlTexture(int plane) Q_DECL_OVERRIDE; + QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const Q_DECL_OVERRIDE { + return QWaylandBufferRef::BufferFormatEgl_RGBA; + } + +private: + QOpenGLTexture *m_texture; + XCompositeEglClientBufferIntegration *m_integration; }; QT_END_NAMESPACE diff --git a/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.cpp b/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.cpp index 6f70d2bbf..0b11c2630 100644 --- a/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.cpp +++ b/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.cpp @@ -41,6 +41,7 @@ #include <qpa/qplatformnativeinterface.h> #include <qpa/qplatformintegration.h> #include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLTexture> #include "xcompositebuffer.h" #include "xcompositehandler.h" @@ -109,14 +110,31 @@ void XCompositeGLXClientBufferIntegration::initializeHardware(struct ::wl_displa delete glContext; } -void XCompositeGLXClientBufferIntegration::bindTextureToBuffer(struct ::wl_resource *buffer) +QtWayland::ClientBuffer *XCompositeGLXClientBufferIntegration::createBufferFor(wl_resource *buffer) { - XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(buffer); - Pixmap pixmap = XCompositeNameWindowPixmap(mDisplay, compositorBuffer->window()); + if (wl_shm_buffer_get(buffer)) + return nullptr; + return new XCompositeGLXClientBuffer(this, buffer); +} + +XCompositeGLXClientBuffer::XCompositeGLXClientBuffer(XCompositeGLXClientBufferIntegration *integration, wl_resource *bufferResource) + : QtWayland::ClientBuffer(bufferResource) + , m_texture(nullptr) + , m_integration(integration) + , m_glxPixmap(0) +{ +} + + +QOpenGLTexture *XCompositeGLXClientBuffer::toOpenGlTexture(int plane) +{ + Q_UNUSED(plane); + XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(m_buffer); + Pixmap pixmap = XCompositeNameWindowPixmap(m_integration->xDisplay(), compositorBuffer->window()); QVector<int> glxConfigSpec = qglx_buildSpec(); int numberOfConfigs; - GLXFBConfig *configs = glXChooseFBConfig(mDisplay,mScreen,glxConfigSpec.constData(),&numberOfConfigs); + GLXFBConfig *configs = glXChooseFBConfig(m_integration->xDisplay(),m_integration->xScreen(),glxConfigSpec.constData(),&numberOfConfigs); QVector<int> attribList; attribList.append(GLX_TEXTURE_FORMAT_EXT); @@ -124,28 +142,40 @@ void XCompositeGLXClientBufferIntegration::bindTextureToBuffer(struct ::wl_resou attribList.append(GLX_TEXTURE_TARGET_EXT); attribList.append(GLX_TEXTURE_2D_EXT); attribList.append(0); - GLXPixmap glxPixmap = glXCreatePixmap(mDisplay,*configs,pixmap,attribList.constData()); + + if (!m_glxPixmap) + m_glxPixmap = glXCreatePixmap(m_integration->xDisplay(), *configs, pixmap, attribList.constData()); uint inverted = 0; - glXQueryDrawable(mDisplay, glxPixmap, GLX_Y_INVERTED_EXT,&inverted); + glXQueryDrawable(m_integration->xDisplay(), m_glxPixmap, GLX_Y_INVERTED_EXT,&inverted); compositorBuffer->setOrigin(inverted ? QWaylandSurface::OriginBottomLeft : QWaylandSurface::OriginTopLeft); XFree(configs); + auto tex = m_texture; + if (!m_texture) { + tex = new QOpenGLTexture(QOpenGLTexture::Target2D); + tex->create(); + m_texture = tex; + } + tex->bind(); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + m_integration->m_glxBindTexImageEXT(m_integration->xDisplay(),m_glxPixmap,GLX_FRONT_EXT, 0); - m_glxBindTexImageEXT(mDisplay,glxPixmap,GLX_FRONT_EXT, 0); - //Do we need to change the api so that we do bind and release in the painevent? - //The specification states that when deleting the texture the color buffer is deleted -// m_glxReleaseTexImageEXT(mDisplay,glxPixmap,GLX_FRONT_EXT); + // TODO: release in the destructor? + // m_glxReleaseTexImageEXT(mDisplay,glxPixmap,GLX_FRONT_EXT); + return tex; } -QWaylandSurface::Origin XCompositeGLXClientBufferIntegration::origin(struct ::wl_resource *buffer) const + +QWaylandSurface::Origin XCompositeGLXClientBuffer::origin() const { - return XCompositeBuffer::fromResource(buffer)->origin(); + XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(m_buffer); + return compositorBuffer->origin(); } -QSize XCompositeGLXClientBufferIntegration::bufferSize(struct ::wl_resource *buffer) const +QSize XCompositeGLXClientBuffer::size() const { - XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(buffer); + XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(m_buffer); return compositorBuffer->size(); } diff --git a/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.h b/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.h index 9caeb4645..7b63f976e 100644 --- a/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.h +++ b/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.h @@ -38,7 +38,7 @@ #define XCOMPOSITEGLXINTEGRATION_H #include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h> - +#include <QtWaylandCompositor/private/qwlclientbuffer_p.h> #include "xlibinclude.h" #define GLX_GLXEXT_PROTOTYPES @@ -56,21 +56,38 @@ public: ~XCompositeGLXClientBufferIntegration(); void initializeHardware(struct ::wl_display *display) Q_DECL_OVERRIDE; + QtWayland::ClientBuffer *createBufferFor(wl_resource *buffer) Q_DECL_OVERRIDE; - void bindTextureToBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; - QWaylandSurface::Origin origin(struct ::wl_resource *) const Q_DECL_OVERRIDE; - - QSize bufferSize(struct ::wl_resource *buffer) const Q_DECL_OVERRIDE; + inline Display *xDisplay() const { return mDisplay; } + inline int xScreen() const { return mScreen; } -private: PFNGLXBINDTEXIMAGEEXTPROC m_glxBindTexImageEXT; PFNGLXRELEASETEXIMAGEEXTPROC m_glxReleaseTexImageEXT; +private: Display *mDisplay; int mScreen; XCompositeHandler *mHandler; }; +class XCompositeGLXClientBuffer : public QtWayland::ClientBuffer +{ +public: + XCompositeGLXClientBuffer(XCompositeGLXClientBufferIntegration *integration, wl_resource *bufferResource); + + QSize size() const; + QWaylandSurface::Origin origin() const; + QOpenGLTexture *toOpenGlTexture(int plane) Q_DECL_OVERRIDE; + QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const Q_DECL_OVERRIDE { + return QWaylandBufferRef::BufferFormatEgl_RGBA; + } + +private: + QOpenGLTexture *m_texture; + XCompositeGLXClientBufferIntegration *m_integration; + GLXPixmap m_glxPixmap; +}; + QT_END_NAMESPACE #endif // XCOMPOSITEGLXINTEGRATION_H |