summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/wayland/minimal-cpp/compositor.cpp14
-rw-r--r--examples/wayland/minimal-cpp/compositor.h5
-rw-r--r--examples/wayland/minimal-cpp/window.cpp6
-rw-r--r--examples/wayland/qwindow-compositor/compositor.cpp25
-rw-r--r--examples/wayland/qwindow-compositor/compositor.h5
-rw-r--r--examples/wayland/qwindow-compositor/window.cpp11
-rw-r--r--src/compositor/compositor_api/qwaylandbufferref.cpp68
-rw-r--r--src/compositor/compositor_api/qwaylandbufferref.h13
-rw-r--r--src/compositor/compositor_api/qwaylandcompositor.cpp16
-rw-r--r--src/compositor/compositor_api/qwaylandcompositor_p.h3
-rw-r--r--src/compositor/compositor_api/qwaylandquickcompositor.cpp13
-rw-r--r--src/compositor/compositor_api/qwaylandquickitem.cpp58
-rw-r--r--src/compositor/compositor_api/qwaylandquickitem_p.h5
-rw-r--r--src/compositor/compositor_api/qwaylandsurface.cpp98
-rw-r--r--src/compositor/compositor_api/qwaylandsurface_p.h10
-rw-r--r--src/compositor/compositor_api/qwaylandview.cpp6
-rw-r--r--src/compositor/compositor_api/qwaylandview_p.h2
-rw-r--r--src/compositor/hardware_integration/qwlclientbufferintegration_p.h16
-rw-r--r--src/compositor/wayland_wrapper/qwlbuffermanager.cpp111
-rw-r--r--src/compositor/wayland_wrapper/qwlbuffermanager_p.h77
-rw-r--r--src/compositor/wayland_wrapper/qwlclientbuffer.cpp189
-rw-r--r--src/compositor/wayland_wrapper/qwlclientbuffer_p.h (renamed from src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h)84
-rw-r--r--src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp261
-rw-r--r--src/compositor/wayland_wrapper/wayland_wrapper.pri6
-rw-r--r--src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.cpp59
-rw-r--r--src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.h22
-rw-r--r--src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp356
-rw-r--r--src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h35
-rw-r--r--src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.cpp50
-rw-r--r--src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.h28
-rw-r--r--src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.cpp58
-rw-r--r--src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.h29
32 files changed, 941 insertions, 798 deletions
diff --git a/examples/wayland/minimal-cpp/compositor.cpp b/examples/wayland/minimal-cpp/compositor.cpp
index ea685923b..5e46895c4 100644
--- a/examples/wayland/minimal-cpp/compositor.cpp
+++ b/examples/wayland/minimal-cpp/compositor.cpp
@@ -44,17 +44,9 @@
#include <QtWaylandCompositor/qwaylandoutput.h>
#include <QOpenGLFunctions>
-GLuint View::getTexture() {
- if (advance()) {
- QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions();
- if (m_texture)
- functions->glDeleteTextures(1, &m_texture);
-
- functions->glGenTextures(1, &m_texture);
- functions->glBindTexture(GL_TEXTURE_2D, m_texture);
- functions->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- currentBuffer().bindToTexture();
- }
+QOpenGLTexture *View::getTexture() {
+ if (advance())
+ m_texture = currentBuffer().toOpenGLTexture();
return m_texture;
}
diff --git a/examples/wayland/minimal-cpp/compositor.h b/examples/wayland/minimal-cpp/compositor.h
index fe379082c..e44a8eb52 100644
--- a/examples/wayland/minimal-cpp/compositor.h
+++ b/examples/wayland/minimal-cpp/compositor.h
@@ -48,17 +48,18 @@
QT_BEGIN_NAMESPACE
class Window;
+class QOpenGLTexture;
class View : public QWaylandView
{
Q_OBJECT
public:
View() : m_texture(0) {}
- GLuint getTexture();
+ QOpenGLTexture *getTexture();
bool isCursor() const;
private:
friend class Compositor;
- GLuint m_texture;
+ QOpenGLTexture *m_texture;
};
class Compositor : public QWaylandCompositor
diff --git a/examples/wayland/minimal-cpp/window.cpp b/examples/wayland/minimal-cpp/window.cpp
index 2d529cce5..6ae89be4f 100644
--- a/examples/wayland/minimal-cpp/window.cpp
+++ b/examples/wayland/minimal-cpp/window.cpp
@@ -44,6 +44,7 @@
#include <QPainter>
#include <QMatrix4x4>
#include <QOpenGLFunctions>
+#include <QOpenGLTexture>
Window::Window()
: m_compositor(0)
@@ -83,7 +84,10 @@ void Window::paintGL()
Q_FOREACH (View *view, m_compositor->views()) {
if (view->isCursor())
continue;
- GLuint textureId = view->getTexture();
+ auto texture = view->getTexture();
+ if (!texture)
+ continue;
+ GLuint textureId = texture->textureId();
QWaylandSurface *surface = view->surface();
if (surface && surface->hasContent()) {
QSize s = surface->size();
diff --git a/examples/wayland/qwindow-compositor/compositor.cpp b/examples/wayland/qwindow-compositor/compositor.cpp
index e9231faf9..a55bb3b72 100644
--- a/examples/wayland/qwindow-compositor/compositor.cpp
+++ b/examples/wayland/qwindow-compositor/compositor.cpp
@@ -65,32 +65,13 @@ View::View()
, m_parentView(nullptr)
{}
-GLuint View::getTexture(GLenum *target)
+QOpenGLTexture *View::getTexture()
{
- QWaylandBufferRef buf = currentBuffer();
- GLuint streamingTexture = buf.textureForPlane(0);
- if (streamingTexture)
- m_texture = streamingTexture;
-
- if (!buf.isSharedMemory() && buf.bufferFormatEgl() == QWaylandBufferRef::BufferFormatEgl_EXTERNAL_OES)
- m_textureTarget = GL_TEXTURE_EXTERNAL_OES;
-
if (advance()) {
- buf = currentBuffer();
- if (!m_texture)
- glGenTextures(1, &m_texture);
-
- glBindTexture(m_textureTarget, m_texture);
- if (buf.isSharedMemory())
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- buf.bindToTexture();
+ QWaylandBufferRef buf = currentBuffer();
+ m_texture = buf.toOpenGLTexture();
}
- buf.updateTexture();
-
- if (target)
- *target = m_textureTarget;
-
return m_texture;
}
diff --git a/examples/wayland/qwindow-compositor/compositor.h b/examples/wayland/qwindow-compositor/compositor.h
index b7569082f..bf52c8c7e 100644
--- a/examples/wayland/qwindow-compositor/compositor.h
+++ b/examples/wayland/qwindow-compositor/compositor.h
@@ -53,13 +53,14 @@ QT_BEGIN_NAMESPACE
class QWaylandWlShell;
class QWaylandWlShellSurface;
class QWaylandXdgShellV5;
+class QOpenGLTexture;
class View : public QWaylandView
{
Q_OBJECT
public:
View();
- GLuint getTexture(GLenum *target = 0);
+ QOpenGLTexture *getTexture();
QPointF position() const { return m_position; }
void setPosition(const QPointF &pos) { m_position = pos; }
bool isCursor() const;
@@ -73,7 +74,7 @@ public:
private:
friend class Compositor;
GLenum m_textureTarget;
- GLuint m_texture;
+ QOpenGLTexture *m_texture;
QPointF m_position;
QWaylandWlShellSurface *m_wlShellSurface;
QWaylandXdgSurfaceV5 *m_xdgSurface;
diff --git a/examples/wayland/qwindow-compositor/window.cpp b/examples/wayland/qwindow-compositor/window.cpp
index 617d79c0e..371e0de80 100644
--- a/examples/wayland/qwindow-compositor/window.cpp
+++ b/examples/wayland/qwindow-compositor/window.cpp
@@ -120,12 +120,11 @@ void Window::paintGL()
Q_FOREACH (View *view, m_compositor->views()) {
if (view->isCursor())
continue;
- GLenum target;
- GLuint textureId = view->getTexture(&target);
- if (!textureId || !target)
+ auto texture = view->getTexture();
+ if (!texture)
continue;
- if (target != currentTarget) {
- currentTarget = target;
+ if (texture->target() != currentTarget) {
+ currentTarget = texture->target();
m_textureBlitter.bind(currentTarget);
}
QWaylandSurface *surface = view->surface();
@@ -141,7 +140,7 @@ void Window::paintGL()
? QOpenGLTextureBlitter::OriginTopLeft
: QOpenGLTextureBlitter::OriginBottomLeft;
QMatrix4x4 targetTransform = QOpenGLTextureBlitter::targetTransform(surfaceGeometry, QRect(QPoint(), size()));
- m_textureBlitter.blit(textureId, targetTransform, surfaceOrigin);
+ m_textureBlitter.blit(texture->textureId(), targetTransform, surfaceOrigin);
}
}
}
diff --git a/src/compositor/compositor_api/qwaylandbufferref.cpp b/src/compositor/compositor_api/qwaylandbufferref.cpp
index 7cc17fcbe..8f7c63f40 100644
--- a/src/compositor/compositor_api/qwaylandbufferref.cpp
+++ b/src/compositor/compositor_api/qwaylandbufferref.cpp
@@ -38,14 +38,14 @@
#include <QAtomicInt>
#include "qwaylandbufferref.h"
-#include "wayland_wrapper/qwlsurfacebuffer_p.h"
+#include "wayland_wrapper/qwlclientbuffer_p.h"
QT_BEGIN_NAMESPACE
class QWaylandBufferRefPrivate
{
public:
- QtWayland::SurfaceBuffer *buffer;
+ QtWayland::ClientBuffer *buffer;
bool nullOrDestroyed() {
return !buffer || buffer->isDestroyed();
@@ -74,7 +74,7 @@ QWaylandBufferRef::QWaylandBufferRef()
/*!
* Constructs a reference to \a buffer.
*/
-QWaylandBufferRef::QWaylandBufferRef(QtWayland::SurfaceBuffer *buffer)
+QWaylandBufferRef::QWaylandBufferRef(QtWayland::ClientBuffer *buffer)
: d(new QWaylandBufferRefPrivate)
{
d->buffer = buffer;
@@ -104,17 +104,18 @@ QWaylandBufferRef::~QWaylandBufferRef()
}
/*!
- * Assigns \a ref to this buffer. The previously referenced buffer is
- * dereferenced and the new one gets a new reference.
+ * Assigns \a ref to this buffer and adds a reference to it. The previously referenced buffer is
+ * dereferenced.
*/
QWaylandBufferRef &QWaylandBufferRef::operator=(const QWaylandBufferRef &ref)
{
+ if (ref.d->buffer)
+ ref.d->buffer->ref();
+
if (d->buffer)
d->buffer->deref();
d->buffer = ref.d->buffer;
- if (d->buffer)
- d->buffer->ref();
return *this;
}
@@ -141,7 +142,7 @@ bool QWaylandBufferRef::operator!=(const QWaylandBufferRef &ref)
* Returns true if this QWaylandBufferRef does not reference a buffer.
* Otherwise returns false.
*
- * \sa hasBuffer()
+ * \sa hasBuffer(), hasContent()
*/
bool QWaylandBufferRef::isNull() const
{
@@ -151,12 +152,21 @@ bool QWaylandBufferRef::isNull() const
/*!
* Returns true if this QWaylandBufferRef references a buffer. Otherwise returns false.
*
- * \sa isNull()
+ * \sa isNull(), hasContent()
*/
bool QWaylandBufferRef::hasBuffer() const
{
return d->buffer;
}
+/*!
+ * Returns true if this QWaylandBufferRef references a buffer that has content. Otherwise returns false.
+ *
+ * \sa isNull(), hasBuffer()
+ */
+bool QWaylandBufferRef::hasContent() const
+{
+ return QtWayland::ClientBuffer::hasContent(d->buffer);
+}
/*!
* Returns true if this QWaylandBufferRef references a buffer that
@@ -176,6 +186,14 @@ struct ::wl_resource *QWaylandBufferRef::wl_buffer() const
}
/*!
+ * \internal
+ */
+QtWayland::ClientBuffer *QWaylandBufferRef::buffer() const
+{
+ return d->buffer;
+}
+
+/*!
* Returns the size of the buffer.
* If the buffer referenced is null, an invalid QSize() is returned.
*/
@@ -242,35 +260,23 @@ QImage QWaylandBufferRef::image() const
}
#ifdef QT_WAYLAND_COMPOSITOR_GL
-GLuint QWaylandBufferRef::textureForPlane(int plane) const
-{
- if (d->nullOrDestroyed())
- return 0;
-
- return d->buffer->textureForPlane(plane);
-}
-
/*!
- * Binds the buffer to the current OpenGL texture. This may
- * perform a copy of the buffer data, depending on the platform
- * and the type of the buffer.
+ * Returns an OpenGL texture for the buffer. \a plane is the index for multi-plane formats, such as YUV.
+ *
+ * The returned texture is owned by the buffer. The texture is only valid for as
+ * long as the buffer reference exists. The caller of this function must not delete the texture, and must
+ * keep a reference to the buffer for as long as the texture is being used.
+ *
+ * Returns \c nullptr if there is no valid buffer, or if no texture can be created.
*/
-void QWaylandBufferRef::bindToTexture() const
+QOpenGLTexture *QWaylandBufferRef::toOpenGLTexture(int plane) const
{
if (d->nullOrDestroyed())
- return;
-
- return d->buffer->bindToTexture();
+ return nullptr;
+ return d->buffer->toOpenGlTexture(plane);
}
-void QWaylandBufferRef::updateTexture() const
-{
- if (d->nullOrDestroyed() || d->buffer->isSharedMemory())
- return;
-
- d->buffer->updateTexture();
-}
#endif
QT_END_NAMESPACE
diff --git a/src/compositor/compositor_api/qwaylandbufferref.h b/src/compositor/compositor_api/qwaylandbufferref.h
index 77f817aba..549ea0a80 100644
--- a/src/compositor/compositor_api/qwaylandbufferref.h
+++ b/src/compositor/compositor_api/qwaylandbufferref.h
@@ -50,22 +50,24 @@ struct wl_resource;
QT_BEGIN_NAMESPACE
+class QOpenGLTexture;
+
namespace QtWayland
{
- class SurfaceBuffer;
+ class ClientBuffer;
}
class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandBufferRef
{
public:
QWaylandBufferRef();
- explicit QWaylandBufferRef(QtWayland::SurfaceBuffer *buffer);
QWaylandBufferRef(const QWaylandBufferRef &ref);
~QWaylandBufferRef();
QWaylandBufferRef &operator=(const QWaylandBufferRef &ref);
bool isNull() const;
bool hasBuffer() const;
+ bool hasContent() const;
bool isDestroyed() const;
bool operator==(const QWaylandBufferRef &ref);
bool operator!=(const QWaylandBufferRef &ref);
@@ -98,14 +100,15 @@ public:
QImage image() const;
#ifdef QT_WAYLAND_COMPOSITOR_GL
- GLuint textureForPlane(int plane) const;
- void bindToTexture() const;
- void updateTexture() const;
+ QOpenGLTexture *toOpenGLTexture(int plane = 0) const;
#endif
private:
+ explicit QWaylandBufferRef(QtWayland::ClientBuffer *buffer);
+ QtWayland::ClientBuffer *buffer() const;
class QWaylandBufferRefPrivate *const d;
friend class QWaylandBufferRefPrivate;
+ friend class QWaylandSurfacePrivate;
};
QT_END_NAMESPACE
diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp
index 0d4e30df7..79a62a1f2 100644
--- a/src/compositor/compositor_api/qwaylandcompositor.cpp
+++ b/src/compositor/compositor_api/qwaylandcompositor.cpp
@@ -53,6 +53,7 @@
#include "wayland_wrapper/qwldatadevice_p.h"
#include "wayland_wrapper/qwldatadevicemanager_p.h"
+#include "wayland_wrapper/qwlbuffermanager_p.h"
#include "hardware_integration/qwlclientbufferintegration_p.h"
#include "hardware_integration/qwlclientbufferintegrationfactory_p.h"
@@ -81,6 +82,7 @@
#ifdef QT_WAYLAND_COMPOSITOR_GL
# include <QOpenGLTextureBlitter>
+# include <QOpenGLTexture>
# include <QOpenGLContext>
# include <QOpenGLFramebufferObject>
# include <QMatrix4x4>
@@ -174,6 +176,7 @@ void QWaylandCompositorPrivate::init()
wl_subcompositor::init(display, 1);
data_device_manager = new QtWayland::DataDeviceManager(q);
+ buffer_manager = new QtWayland::BufferManager(q);
wl_display_init_shm(display);
QVector<wl_shm_format> formats = QWaylandSharedMemoryFormatHelper::supportedWaylandFormats();
@@ -895,7 +898,7 @@ void QWaylandCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const QWay
fbo.bind();
QOpenGLTextureBlitter blitter;
blitter.create();
- blitter.bind();
+
glViewport(0, 0, buffer.size().width(), buffer.size().height());
@@ -904,15 +907,10 @@ void QWaylandCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const QWay
? QOpenGLTextureBlitter::OriginTopLeft
: QOpenGLTextureBlitter::OriginBottomLeft;
- GLuint texture;
- glGenTextures(1, &texture);
- glBindTexture(GL_TEXTURE_2D, texture);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- buffer.bindToTexture();
- blitter.blit(texture, QMatrix4x4(), surfaceOrigin);
-
+ auto texture = buffer.toOpenGLTexture();
+ blitter.bind(texture->target());
+ blitter.blit(texture->textureId(), QMatrix4x4(), surfaceOrigin);
blitter.release();
- glDeleteTextures(1, &texture);
emit grabber->success(fbo.toImage());
} else
diff --git a/src/compositor/compositor_api/qwaylandcompositor_p.h b/src/compositor/compositor_api/qwaylandcompositor_p.h
index 9942331e4..5255f3d58 100644
--- a/src/compositor/compositor_api/qwaylandcompositor_p.h
+++ b/src/compositor/compositor_api/qwaylandcompositor_p.h
@@ -64,6 +64,7 @@ namespace QtWayland {
class ClientBufferIntegration;
class ServerBufferIntegration;
class DataDeviceManager;
+ class BufferManager;
}
class QWindowSystemEventHandler;
@@ -89,6 +90,7 @@ public:
inline QtWayland::ServerBufferIntegration *serverBufferIntegration() const;
QtWayland::DataDeviceManager *dataDeviceManager() const { return data_device_manager; }
+ QtWayland::BufferManager *bufferManager() const { return buffer_manager; }
void feedRetainedSelectionData(QMimeData *data);
QWaylandPointer *callCreatePointerDevice(QWaylandSeat *seat)
@@ -129,6 +131,7 @@ protected:
QList<QWaylandSurface *> all_surfaces;
QtWayland::DataDeviceManager *data_device_manager;
+ QtWayland::BufferManager *buffer_manager;
QElapsedTimer timer;
diff --git a/src/compositor/compositor_api/qwaylandquickcompositor.cpp b/src/compositor/compositor_api/qwaylandquickcompositor.cpp
index 21e32573e..b69e20791 100644
--- a/src/compositor/compositor_api/qwaylandquickcompositor.cpp
+++ b/src/compositor/compositor_api/qwaylandquickcompositor.cpp
@@ -38,6 +38,7 @@
#include <QtQml/QQmlEngine>
#include <QQuickWindow>
#include <QOpenGLTextureBlitter>
+#include <QOpenGLTexture>
#include <QOpenGLFramebufferObject>
#include <QMatrix4x4>
#include <QRunnable>
@@ -140,7 +141,6 @@ void QWaylandQuickCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const
fbo.bind();
QOpenGLTextureBlitter blitter;
blitter.create();
- blitter.bind();
glViewport(0, 0, buffer.size().width(), buffer.size().height());
@@ -149,15 +149,10 @@ void QWaylandQuickCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const
? QOpenGLTextureBlitter::OriginTopLeft
: QOpenGLTextureBlitter::OriginBottomLeft;
- GLuint texture;
- glGenTextures(1, &texture);
- glBindTexture(GL_TEXTURE_2D, texture);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- buffer.bindToTexture();
- blitter.blit(texture, QMatrix4x4(), surfaceOrigin);
-
+ auto texture = buffer.toOpenGLTexture();
+ blitter.bind(texture->target());
+ blitter.blit(texture->textureId(), QMatrix4x4(), surfaceOrigin);
blitter.release();
- glDeleteTextures(1, &texture);
emit grabber->success(fbo.toImage());
}
diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp
index a3234cba6..f41a4c3ee 100644
--- a/src/compositor/compositor_api/qwaylandquickitem.cpp
+++ b/src/compositor/compositor_api/qwaylandquickitem.cpp
@@ -50,6 +50,7 @@
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
#include <QtGui/QOpenGLFunctions>
+#include <QtGui/QOpenGLTexture>
#include <QtQuick/QSGSimpleTextureNode>
#include <QtQuick/QQuickWindow>
@@ -188,52 +189,40 @@ QWaylandBufferMaterial::QWaylandBufferMaterial(QWaylandBufferRef::BufferFormatEg
QWaylandBufferMaterial::~QWaylandBufferMaterial()
{
- QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions();
-
- for (GLuint texture : m_textures)
- gl->glDeleteTextures(1, &texture);
}
-void QWaylandBufferMaterial::setTextureForPlane(int plane, uint texture)
+void QWaylandBufferMaterial::setTextureForPlane(int plane, QOpenGLTexture *texture)
{
if (plane < 0 || plane >= bufferTypes[m_format].planeCount) {
qWarning("plane index is out of range");
return;
}
- QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions();
- const GLenum target = bufferTypes[m_format].textureTarget;
-
- gl->glBindTexture(target, texture);
- setTextureParameters(target);
+ texture->bind();
+ setTextureParameters(texture->target());
ensureTextures(plane - 1);
- if (m_textures.size() <= plane) {
+ if (m_textures.size() <= plane)
m_textures << texture;
- } else {
- std::swap(m_textures[plane], texture);
- gl->glDeleteTextures(1, &texture);
- }
+ else
+ m_textures[plane] = texture;
}
void QWaylandBufferMaterial::bind()
{
- QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions();
- const GLenum target = bufferTypes[m_format].textureTarget;
-
ensureTextures(bufferTypes[m_format].planeCount);
switch (m_textures.size()) {
case 3:
- gl->glActiveTexture(GL_TEXTURE2);
- gl->glBindTexture(target, m_textures[2]);
+ if (m_textures[2])
+ m_textures[2]->bind(GL_TEXTURE2);
case 2:
- gl->glActiveTexture(GL_TEXTURE1);
- gl->glBindTexture(target, m_textures[1]);
+ if (m_textures[1])
+ m_textures[1]->bind(GL_TEXTURE1);
case 1:
- gl->glActiveTexture(GL_TEXTURE0);
- gl->glBindTexture(target, m_textures[0]);
+ if (m_textures[0])
+ m_textures[0]->bind(GL_TEXTURE0);
}
}
@@ -260,15 +249,8 @@ void QWaylandBufferMaterial::setTextureParameters(GLenum target)
//TODO move this into a separate centralized texture management class
void QWaylandBufferMaterial::ensureTextures(int count)
{
- QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions();
- const GLenum target = bufferTypes[m_format].textureTarget;
- GLuint texture;
-
for (int plane = m_textures.size(); plane < count; plane++) {
- gl->glGenTextures(1, &texture);
- gl->glBindTexture(target, texture);
- setTextureParameters(target);
- m_textures << texture;
+ m_textures << nullptr;
}
}
@@ -308,11 +290,8 @@ public:
opt |= QQuickWindow::TextureHasAlphaChannel;
}
- GLuint texture;
- glGenTextures(1, &texture);
- glBindTexture(GL_TEXTURE_2D, texture);
- buffer.bindToTexture();
- m_sgTex = surfaceItem->window()->createTextureFromId(texture , QSize(surfaceItem->width(), surfaceItem->height()), opt);
+ auto texture = buffer.toOpenGLTexture();
+ m_sgTex = surfaceItem->window()->createTextureFromId(texture->textureId() , QSize(surfaceItem->width(), surfaceItem->height()), opt);
}
}
emit textureChanged();
@@ -1151,6 +1130,7 @@ QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
: QRectF(0, 0, width(), height());
if (ref.isSharedMemory() || bufferTypes[ref.bufferFormatEgl()].canProvideTexture) {
+ // This case could covered by the more general path below, but this is more efficient (especially when using ShaderEffect items).
QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>(oldNode);
if (!node) {
@@ -1193,13 +1173,11 @@ QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->newTexture) {
d->newTexture = false;
for (int plane = 0; plane < bufferTypes[ref.bufferFormatEgl()].planeCount; plane++)
- if (uint texture = ref.textureForPlane(plane))
+ if (auto texture = ref.toOpenGLTexture(plane))
material->setTextureForPlane(plane, texture);
material->bind();
- ref.bindToTexture();
}
- ref.updateTexture();
QSGGeometry::updateTexturedRectGeometry(geometry, rect, QRectF(0, 0, 1, 1));
node->setGeometry(geometry);
diff --git a/src/compositor/compositor_api/qwaylandquickitem_p.h b/src/compositor/compositor_api/qwaylandquickitem_p.h
index 30f1e93c7..c30829926 100644
--- a/src/compositor/compositor_api/qwaylandquickitem_p.h
+++ b/src/compositor/compositor_api/qwaylandquickitem_p.h
@@ -59,6 +59,7 @@ QT_BEGIN_NAMESPACE
class QWaylandSurfaceTextureProvider;
class QMutex;
+class QOpenGLTexture;
class QWaylandBufferMaterialShader : public QSGMaterialShader
{
@@ -84,7 +85,7 @@ public:
QWaylandBufferMaterial(QWaylandBufferRef::BufferFormatEgl format);
~QWaylandBufferMaterial();
- void setTextureForPlane(int plane, uint texture);
+ void setTextureForPlane(int plane, QOpenGLTexture *texture);
void bind();
@@ -96,7 +97,7 @@ private:
void ensureTextures(int count);
const QWaylandBufferRef::BufferFormatEgl m_format;
- QVarLengthArray<GLuint, 3> m_textures;
+ QVarLengthArray<QOpenGLTexture*, 3> m_textures;
};
class QWaylandQuickItemPrivate : public QQuickItemPrivate
diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp
index c00d765c5..2f4de5cfc 100644
--- a/src/compositor/compositor_api/qwaylandsurface.cpp
+++ b/src/compositor/compositor_api/qwaylandsurface.cpp
@@ -40,6 +40,7 @@
#include "wayland_wrapper/qwldatadevice_p.h"
#include "wayland_wrapper/qwldatadevicemanager_p.h"
+#include "wayland_wrapper/qwlbuffermanager_p.h"
#include "wayland_wrapper/qwlregion_p.h"
#include "extensions/qwlextendedsurface_p.h"
@@ -123,7 +124,6 @@ QWaylandSurfacePrivate::QWaylandSurfacePrivate()
, compositor(Q_NULLPTR)
, refCount(1)
, client(Q_NULLPTR)
- , buffer(0)
, role(0)
, inputRegion(infiniteRegion())
, bufferScale(1)
@@ -135,7 +135,7 @@ QWaylandSurfacePrivate::QWaylandSurfacePrivate()
, inputMethodControl(Q_NULLPTR)
, subsurface(0)
{
- pending.buffer = 0;
+ pending.buffer = QWaylandBufferRef();
pending.newlyAttached = false;
pending.inputRegion = infiniteRegion();
pending.bufferScale = 1;
@@ -153,9 +153,6 @@ QWaylandSurfacePrivate::~QWaylandSurfacePrivate()
bufferRef = QWaylandBufferRef();
- for (int i = 0; i < bufferPool.size(); i++)
- bufferPool[i]->setDestroyIfUnused(true);
-
foreach (QtWayland::FrameCallback *c, pendingFrameCallbacks)
c->destroy();
foreach (QtWayland::FrameCallback *c, frameCallbacks)
@@ -237,9 +234,7 @@ void QWaylandSurfacePrivate::surface_destroy(Resource *resource)
void QWaylandSurfacePrivate::surface_attach(Resource *, struct wl_resource *buffer, int x, int y)
{
- if (pending.buffer)
- pending.buffer->disown();
- pending.buffer = createSurfaceBuffer(buffer);
+ pending.buffer = QWaylandBufferRef(getBuffer(buffer));
pending.offset = QPoint(x, y);
pending.newlyAttached = true;
}
@@ -274,19 +269,37 @@ void QWaylandSurfacePrivate::surface_commit(Resource *)
{
Q_Q(QWaylandSurface);
- if (pending.buffer || pending.newlyAttached) {
- setBackBuffer(pending.buffer, pending.damage);
+ if (pending.buffer.hasBuffer())
+ bufferRef = pending.buffer;
+
+ auto buffer = bufferRef.buffer();
+ if (buffer)
+ buffer->setCommitted(pending.damage);
+
+ setSize(bufferRef.size());
+ damage = pending.damage.intersected(QRect(QPoint(), size));
+
+ for (int i = 0; i < views.size(); i++) {
+ views.at(i)->bufferCommitted(bufferRef, damage);
}
- pending.buffer = 0;
- pending.offset = QPoint();
- pending.newlyAttached = false;
- pending.damage = QRegion();
+ emit q->damaged(damage);
+
+ bool oldHasContent = hasContent;
+ hasContent = bufferRef.hasContent();
+ if (oldHasContent != hasContent)
+ emit q->hasContentChanged();
+
+ if (!pending.offset.isNull())
+ emit q->offsetForNextFrame(pending.offset);
setBufferScale(pending.bufferScale);
- if (buffer)
- buffer->setCommitted();
+
+ pending.buffer = QWaylandBufferRef();
+ pending.offset = QPoint();
+ pending.newlyAttached = false;
+ pending.damage = QRegion();
frameCallbacks << pendingFrameCallbacks;
pendingFrameCallbacks.clear();
@@ -326,52 +339,10 @@ void QWaylandSurfacePrivate::surface_set_buffer_scale(QtWaylandServer::wl_surfac
pending.bufferScale = scale;
}
-void QWaylandSurfacePrivate::setBackBuffer(QtWayland::SurfaceBuffer *b, const QRegion &d)
+QtWayland::ClientBuffer *QWaylandSurfacePrivate::getBuffer(struct ::wl_resource *buffer)
{
- Q_Q(QWaylandSurface);
- buffer = b;
-
- bufferRef = QWaylandBufferRef(buffer);
-
- setSize(bufferRef.size());
- damage = d.intersected(QRect(QPoint(), size));
-
- for (int i = 0; i < views.size(); i++) {
- views.at(i)->bufferCommitted(bufferRef, damage);
- }
-
- emit q->damaged(damage);
-
- bool oldHasContent = hasContent;
- hasContent = QtWayland::SurfaceBuffer::hasContent(buffer);
- if (oldHasContent != hasContent)
- emit q->hasContentChanged();
-
- if (!pending.offset.isNull())
- emit q->offsetForNextFrame(pending.offset);
-}
-
-QtWayland::SurfaceBuffer *QWaylandSurfacePrivate::createSurfaceBuffer(struct ::wl_resource *buffer)
-{
- Q_Q(QWaylandSurface);
- QtWayland::SurfaceBuffer *newBuffer = 0;
- for (int i = 0; i < bufferPool.size(); i++) {
- if (!bufferPool[i]->isRegisteredWithBuffer()) {
- newBuffer = bufferPool[i];
- newBuffer->initialize(buffer);
- break;
- }
- }
-
- if (!newBuffer) {
- newBuffer = new QtWayland::SurfaceBuffer(q);
- newBuffer->initialize(buffer);
- bufferPool.append(newBuffer);
- if (bufferPool.size() > 3)
- qWarning() << "Increased buffer pool size to" << bufferPool.size() << "for surface" << q;
- }
-
- return newBuffer;
+ QtWayland::BufferManager *bufMan = QWaylandCompositorPrivate::get(compositor)->bufferManager();
+ return bufMan->getBuffer(buffer);
}
/*!
@@ -590,7 +561,7 @@ Qt::ScreenOrientation QWaylandSurface::contentOrientation() const
QWaylandSurface::Origin QWaylandSurface::origin() const
{
Q_D(const QWaylandSurface);
- return d->buffer ? d->buffer->origin() : QWaylandSurface::OriginTopLeft;
+ return d->bufferRef.origin();
}
/*!
@@ -835,8 +806,7 @@ void QWaylandSurfacePrivate::refView(QWaylandView *view)
views.append(view);
ref();
- QWaylandBufferRef ref(buffer);
- view->bufferCommitted(ref, QRect(QPoint(0,0), ref.size()));
+ view->bufferCommitted(bufferRef, QRect(QPoint(0,0), bufferRef.size()));
}
void QWaylandSurfacePrivate::derefView(QWaylandView *view)
diff --git a/src/compositor/compositor_api/qwaylandsurface_p.h b/src/compositor/compositor_api/qwaylandsurface_p.h
index 0596b61ba..94ec287bd 100644
--- a/src/compositor/compositor_api/qwaylandsurface_p.h
+++ b/src/compositor/compositor_api/qwaylandsurface_p.h
@@ -52,7 +52,7 @@
#include <QtWaylandCompositor/qwaylandexport.h>
#include <private/qobject_p.h>
-#include <private/qwlsurfacebuffer_p.h>
+#include <private/qwlclientbuffer_p.h>
#include <QtWaylandCompositor/qwaylandsurface.h>
#include <QtWaylandCompositor/qwaylandbufferref.h>
@@ -134,8 +134,7 @@ protected:
void surface_set_buffer_transform(Resource *resource, int32_t transform) Q_DECL_OVERRIDE;
void surface_set_buffer_scale(Resource *resource, int32_t bufferScale) Q_DECL_OVERRIDE;
- void setBackBuffer(QtWayland::SurfaceBuffer *buffer, const QRegion &damage);
- QtWayland::SurfaceBuffer *createSurfaceBuffer(struct ::wl_resource *buffer);
+ QtWayland::ClientBuffer *getBuffer(struct ::wl_resource *buffer);
public: //member variables
QWaylandCompositor *compositor;
@@ -143,12 +142,11 @@ public: //member variables
QWaylandClient *client;
QList<QWaylandView *> views;
QRegion damage;
- QtWayland::SurfaceBuffer *buffer;
QWaylandBufferRef bufferRef;
QWaylandSurfaceRole *role;
struct {
- QtWayland::SurfaceBuffer *buffer;
+ QWaylandBufferRef buffer;
QRegion damage;
QPoint offset;
bool newlyAttached;
@@ -165,8 +163,6 @@ public: //member variables
QRegion inputRegion;
QRegion opaqueRegion;
- QVector<QtWayland::SurfaceBuffer *> bufferPool;
-
QSize size;
int bufferScale;
bool isCursorSurface;
diff --git a/src/compositor/compositor_api/qwaylandview.cpp b/src/compositor/compositor_api/qwaylandview.cpp
index 5b87eae21..850503847 100644
--- a/src/compositor/compositor_api/qwaylandview.cpp
+++ b/src/compositor/compositor_api/qwaylandview.cpp
@@ -151,6 +151,7 @@ void QWaylandView::setSurface(QWaylandSurface *newSurface)
}
d->nextBuffer = QWaylandBufferRef();
+ d->nextBufferCommitted = false;
d->nextDamage = QRegion();
if (d->surface) {
@@ -211,6 +212,7 @@ void QWaylandView::bufferCommitted(const QWaylandBufferRef &buffer, const QRegio
QMutexLocker locker(&d->bufferMutex);
d->nextBuffer = buffer;
d->nextDamage = damage;
+ d->nextBufferCommitted = true;
}
/*!
@@ -232,7 +234,8 @@ void QWaylandView::bufferCommitted(const QWaylandBufferRef &buffer, const QRegio
bool QWaylandView::advance()
{
Q_D(QWaylandView);
- if (d->currentBuffer == d->nextBuffer && !d->forceAdvanceSucceed)
+
+ if (!d->nextBufferCommitted && !d->forceAdvanceSucceed)
return false;
if (d->bufferLocked)
@@ -247,6 +250,7 @@ bool QWaylandView::advance()
QMutexLocker locker(&d->bufferMutex);
d->forceAdvanceSucceed = false;
+ d->nextBufferCommitted = false;
d->currentBuffer = d->nextBuffer;
d->currentDamage = d->nextDamage;
return true;
diff --git a/src/compositor/compositor_api/qwaylandview_p.h b/src/compositor/compositor_api/qwaylandview_p.h
index d9fd352ed..8c55eca36 100644
--- a/src/compositor/compositor_api/qwaylandview_p.h
+++ b/src/compositor/compositor_api/qwaylandview_p.h
@@ -69,6 +69,7 @@ public:
: renderObject(Q_NULLPTR)
, surface(Q_NULLPTR)
, output(Q_NULLPTR)
+ , nextBufferCommitted(false)
, bufferLocked(false)
, broadcastRequestedPositionChanged(false)
, forceAdvanceSucceed(false)
@@ -86,6 +87,7 @@ public:
QRegion currentDamage;
QWaylandBufferRef nextBuffer;
QRegion nextDamage;
+ bool nextBufferCommitted;
bool bufferLocked;
bool broadcastRequestedPositionChanged;
bool forceAdvanceSucceed;
diff --git a/src/compositor/hardware_integration/qwlclientbufferintegration_p.h b/src/compositor/hardware_integration/qwlclientbufferintegration_p.h
index 90762437b..a7de2c0e3 100644
--- a/src/compositor/hardware_integration/qwlclientbufferintegration_p.h
+++ b/src/compositor/hardware_integration/qwlclientbufferintegration_p.h
@@ -57,6 +57,7 @@
QT_BEGIN_NAMESPACE
class QWaylandCompositor;
+class QOpenGLTexture;
namespace QtWayland {
class Display;
@@ -68,22 +69,11 @@ public:
virtual ~ClientBufferIntegration() { }
void setCompositor(QWaylandCompositor *compositor) { m_compositor = compositor; }
+ QWaylandCompositor *compositor() const { return m_compositor; }
virtual void initializeHardware(struct ::wl_display *display) = 0;
- virtual void initializeBuffer(struct ::wl_resource *buffer) { Q_UNUSED(buffer); }
- virtual QWaylandBufferRef::BufferFormatEgl bufferFormat(struct ::wl_resource *buffer) { Q_UNUSED(buffer); return QWaylandBufferRef::BufferFormatEgl_RGBA; }
- virtual uint textureForBuffer(struct ::wl_resource *buffer, int plane) { Q_UNUSED(buffer); Q_UNUSED(plane); return 0; }
-
- virtual void bindTextureToBuffer(struct ::wl_resource *buffer) = 0;
- virtual void updateTextureForBuffer(struct ::wl_resource *buffer) { Q_UNUSED(buffer); }
-
- virtual QWaylandSurface::Origin origin(struct ::wl_resource *) const { return QWaylandSurface::OriginBottomLeft; }
-
- virtual void *lockNativeBuffer(struct ::wl_resource *) const { return 0; }
- virtual void unlockNativeBuffer(void *) const { return; }
-
- virtual QSize bufferSize(struct ::wl_resource *) const { return QSize(); }
+ virtual ClientBuffer *createBufferFor(struct ::wl_resource *buffer) = 0;
protected:
QWaylandCompositor *m_compositor;
diff --git a/src/compositor/wayland_wrapper/qwlbuffermanager.cpp b/src/compositor/wayland_wrapper/qwlbuffermanager.cpp
new file mode 100644
index 000000000..765c9a03a
--- /dev/null
+++ b/src/compositor/wayland_wrapper/qwlbuffermanager.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwlbuffermanager_p.h"
+#include <QWaylandCompositor>
+#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
+#include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWayland {
+
+BufferManager::BufferManager(QWaylandCompositor *compositor)
+ : QObject(compositor)
+ , m_compositor(compositor)
+{
+
+}
+
+struct buffer_manager_destroy_listener : wl_listener
+{
+ buffer_manager_destroy_listener()
+ : d(0)
+ {
+ notify = BufferManager::destroy_listener_callback;
+ wl_list_init(&this->link);
+ }
+
+ BufferManager *d;
+};
+
+ClientBuffer *BufferManager::getBuffer(wl_resource *buffer_resource)
+{
+ if (!buffer_resource)
+ return nullptr;
+
+ auto it = m_buffers.find(buffer_resource);
+ if (it != m_buffers.end())
+ return it.value();
+
+ auto bufferIntegration = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration();
+ ClientBuffer *newBuffer = nullptr;
+ if (bufferIntegration)
+ newBuffer = bufferIntegration->createBufferFor(buffer_resource);
+ if (!newBuffer)
+ newBuffer = new SharedMemoryBuffer(buffer_resource);
+ m_buffers[buffer_resource] = newBuffer;
+
+ auto *destroy_listener = new buffer_manager_destroy_listener;
+ destroy_listener->d = this;
+ wl_signal_add(&buffer_resource->destroy_signal, destroy_listener);
+ return newBuffer;
+}
+
+
+void BufferManager::destroy_listener_callback(wl_listener *listener, void *data)
+{
+ buffer_manager_destroy_listener *destroy_listener = static_cast<buffer_manager_destroy_listener *>(listener);
+ BufferManager *self = destroy_listener->d;
+ struct ::wl_resource *buffer = static_cast<struct ::wl_resource *>(data);
+
+ wl_list_remove(&destroy_listener->link);
+ delete destroy_listener;
+
+ Q_ASSERT(self);
+ Q_ASSERT(buffer);
+
+ ClientBuffer *clientBuffer = self->m_buffers.take(buffer);
+
+ if (!clientBuffer)
+ return;
+
+ clientBuffer->setDestroyed();
+}
+
+}
+QT_END_NAMESPACE
diff --git a/src/compositor/wayland_wrapper/qwlbuffermanager_p.h b/src/compositor/wayland_wrapper/qwlbuffermanager_p.h
new file mode 100644
index 000000000..e1325ef89
--- /dev/null
+++ b/src/compositor/wayland_wrapper/qwlbuffermanager_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWLBUFFERMANAGER_H
+#define QWLBUFFERMANAGER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QObject>
+#include "qwlclientbuffer_p.h"
+QT_BEGIN_NAMESPACE
+
+class QWaylandCompositor;
+
+namespace QtWayland {
+
+class ClientBuffer;
+
+class Q_WAYLAND_COMPOSITOR_EXPORT BufferManager : public QObject
+{
+public:
+ BufferManager(QWaylandCompositor *compositor);
+ ClientBuffer *getBuffer(struct ::wl_resource *buffer_resource);
+private:
+ friend struct buffer_manager_destroy_listener;
+ static void destroy_listener_callback(wl_listener *listener, void *data);
+
+ QHash<struct ::wl_resource *, ClientBuffer*> m_buffers;
+ QWaylandCompositor *m_compositor;
+};
+
+}
+QT_END_NAMESPACE
+
+#endif // QWLBUFFERMANAGER_H
diff --git a/src/compositor/wayland_wrapper/qwlclientbuffer.cpp b/src/compositor/wayland_wrapper/qwlclientbuffer.cpp
new file mode 100644
index 000000000..589ab825b
--- /dev/null
+++ b/src/compositor/wayland_wrapper/qwlclientbuffer.cpp
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwlclientbuffer_p.h"
+
+#ifdef QT_WAYLAND_COMPOSITOR_GL
+#include "hardware_integration/qwlclientbufferintegration_p.h"
+#include <qpa/qplatformopenglcontext.h>
+#include <QOpenGLTexture>
+#endif
+
+#include <QtCore/QDebug>
+
+#include <wayland-server-protocol.h>
+#include "qwaylandsharedmemoryformathelper_p.h"
+
+#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWayland {
+
+ClientBuffer::ClientBuffer(struct ::wl_resource *buffer)
+ : m_buffer(buffer)
+ , m_textureDirty(false)
+ , m_committed(false)
+ , m_destroyed(false)
+{
+}
+
+
+ClientBuffer::~ClientBuffer()
+{
+ if (m_buffer && m_committed && !m_destroyed)
+ sendRelease();
+}
+
+void ClientBuffer::sendRelease()
+{
+ Q_ASSERT(m_buffer);
+ wl_buffer_send_release(m_buffer);
+ m_committed = false;
+}
+
+void ClientBuffer::setDestroyed()
+{
+ m_destroyed = true;
+ m_committed = false;
+ m_buffer = nullptr;
+
+ if (!m_refCount)
+ delete this;
+}
+
+void ClientBuffer::ref()
+{
+ m_refCount.ref();
+}
+
+void ClientBuffer::deref()
+{
+ if (!m_refCount.deref()) {
+ if (isCommitted() && m_buffer && !m_destroyed)
+ sendRelease();
+ if (m_destroyed)
+ delete this;
+ }
+}
+
+void ClientBuffer::setCommitted(QRegion &damage)
+{
+ m_damage = damage;
+ m_committed = true;
+ m_textureDirty = true;
+}
+
+QWaylandBufferRef::BufferFormatEgl ClientBuffer::bufferFormatEgl() const
+{
+ return QWaylandBufferRef::BufferFormatEgl_Null;
+}
+
+SharedMemoryBuffer::SharedMemoryBuffer(wl_resource *bufferResource)
+ : ClientBuffer(bufferResource)
+ , m_shmTexture(nullptr)
+{
+
+}
+
+QSize SharedMemoryBuffer::size() const
+{
+ if (wl_shm_buffer *shmBuffer = wl_shm_buffer_get(m_buffer)) {
+ int width = wl_shm_buffer_get_width(shmBuffer);
+ int height = wl_shm_buffer_get_height(shmBuffer);
+ return QSize(width, height);
+ }
+ return QSize();
+}
+
+QWaylandSurface::Origin SharedMemoryBuffer::origin() const
+{
+ return QWaylandSurface::OriginTopLeft;
+}
+
+
+// TODO: support different color formats, and try to avoid QImage::convertToFormat()
+
+QImage SharedMemoryBuffer::image() const
+{
+ if (wl_shm_buffer *shmBuffer = wl_shm_buffer_get(m_buffer)) {
+ int width = wl_shm_buffer_get_width(shmBuffer);
+ int height = wl_shm_buffer_get_height(shmBuffer);
+ int bytesPerLine = wl_shm_buffer_get_stride(shmBuffer);
+ uchar *data = static_cast<uchar *>(wl_shm_buffer_get_data(shmBuffer));
+ return QImage(data, width, height, bytesPerLine, QImage::Format_ARGB32_Premultiplied);
+ }
+
+ return QImage();
+}
+
+#ifdef QT_WAYLAND_COMPOSITOR_GL
+QOpenGLTexture *SharedMemoryBuffer::toOpenGlTexture(int plane)
+{
+ Q_UNUSED(plane);
+ if (isSharedMemory()) {
+ if (!m_shmTexture) {
+ m_shmTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);
+ m_shmTexture->create();
+ }
+ if (m_textureDirty) {
+ m_textureDirty = false;
+ m_shmTexture->bind();
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ // TODO: partial texture upload
+ QImage image = this->image();
+ if (image.hasAlphaChannel()) {
+ if (image.format() != QImage::Format_RGBA8888)
+ image = image.convertToFormat(QImage::Format_RGBA8888);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.constBits());
+ } else {
+ if (image.format() != QImage::Format_RGBX8888)
+ image = image.convertToFormat(QImage::Format_RGBX8888);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, image.constBits());
+ }
+ //we can release the buffer after uploading, since we have a copy
+ if (isCommitted())
+ sendRelease();
+ }
+ return m_shmTexture;
+ }
+ return nullptr;
+}
+#endif
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h b/src/compositor/wayland_wrapper/qwlclientbuffer_p.h
index e0a7d021f..72c5a56e3 100644
--- a/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h
+++ b/src/compositor/wayland_wrapper/qwlclientbuffer_p.h
@@ -34,8 +34,8 @@
**
****************************************************************************/
-#ifndef SURFACEBUFFER_H
-#define SURFACEBUFFER_H
+#ifndef QWLCLIENTBUFFER_P_H
+#define QWLCLIENTBUFFER_P_H
//
// W A R N I N G
@@ -63,83 +63,85 @@ QT_BEGIN_NAMESPACE
class QWaylandClientBufferIntegration;
class QWaylandBufferRef;
class QWaylandCompositor;
+class QOpenGLTexture;
namespace QtWayland {
struct surface_buffer_destroy_listener
{
struct wl_listener listener;
- class SurfaceBuffer *surfaceBuffer;
+ class ClientBuffer *surfaceBuffer;
};
-class SurfaceBuffer
+class Q_WAYLAND_COMPOSITOR_EXPORT ClientBuffer
{
public:
- SurfaceBuffer(QWaylandSurface *surface);
+ ClientBuffer(struct ::wl_resource *bufferResource);
- ~SurfaceBuffer();
+ virtual ~ClientBuffer();
- void initialize(struct ::wl_resource *bufferResource);
- void destructBufferState();
+ virtual QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const;
+ virtual QSize size() const = 0;
+ virtual QWaylandSurface::Origin origin() const = 0;
- inline bool isRegisteredWithBuffer() const { return m_is_registered_for_buffer; }
+ virtual void *lockNativeBuffer() { return nullptr; }
+ virtual void unlockNativeBuffer(void *native_buffer) const { Q_UNUSED(native_buffer); }
- void sendRelease();
- void disown();
-
- void setDisplayed();
+ virtual QImage image() const { return QImage(); }
inline bool isCommitted() const { return m_committed; }
- inline void setCommitted() { m_committed = true; }
- inline bool isDisplayed() const { return m_is_displayed; }
-
+ virtual void setCommitted(QRegion &damage);
bool isDestroyed() { return m_destroyed; }
inline struct ::wl_resource *waylandBufferHandle() const { return m_buffer; }
- void setDestroyIfUnused(bool destroy);
-
- QSize size() const;
- QWaylandSurface::Origin origin() const;
bool isSharedMemory() const { return wl_shm_buffer_get(m_buffer); }
- QImage image() const;
- QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const;
#ifdef QT_WAYLAND_COMPOSITOR_GL
- void bindToTexture() const;
- uint textureForPlane(int plane) const;
- void updateTexture() const;
+ virtual QOpenGLTexture *toOpenGlTexture(int plane = 0) = 0;
#endif
- static bool hasContent(SurfaceBuffer *buffer) { return buffer && buffer->waylandBufferHandle(); }
-private:
+ static bool hasContent(ClientBuffer *buffer) { return buffer && buffer->waylandBufferHandle(); }
+
+protected:
void ref();
void deref();
- void destroyIfUnused();
+ void sendRelease();
+ void setDestroyed();
- QWaylandSurface *m_surface;
- QWaylandCompositor *m_compositor;
struct ::wl_resource *m_buffer;
- int m_bufferScale;
- struct surface_buffer_destroy_listener m_destroy_listener;
+ QRegion m_damage;
+ bool m_textureDirty;
+
+private:
bool m_committed;
- bool m_is_registered_for_buffer;
- bool m_surface_has_buffer;
bool m_destroyed;
- bool m_is_displayed;
-
QAtomicInt m_refCount;
- bool m_used;
- bool m_destroyIfUnused;
-
- static void destroy_listener_callback(wl_listener *listener, void *data);
friend class ::QWaylandBufferRef;
+ friend class BufferManager;
+};
+
+class Q_WAYLAND_COMPOSITOR_EXPORT SharedMemoryBuffer : public ClientBuffer
+{
+public:
+ SharedMemoryBuffer(struct ::wl_resource *bufferResource);
+
+ QSize size() const Q_DECL_OVERRIDE;
+ QWaylandSurface::Origin origin() const Q_DECL_OVERRIDE;
+ QImage image() const;
+
+#ifdef QT_WAYLAND_COMPOSITOR_GL
+ QOpenGLTexture *toOpenGlTexture(int plane = 0) Q_DECL_OVERRIDE;
+
+private:
+ QOpenGLTexture *m_shmTexture;
+#endif
};
}
QT_END_NAMESPACE
-#endif // SURFACEBUFFER_H
+#endif // QWLCLIENTBUFFER_P_H
diff --git a/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp b/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp
deleted file mode 100644
index df2dded2f..000000000
--- a/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwlsurfacebuffer_p.h"
-
-#ifdef QT_WAYLAND_COMPOSITOR_GL
-#include "hardware_integration/qwlclientbufferintegration_p.h"
-#include <qpa/qplatformopenglcontext.h>
-#endif
-
-#include <QtCore/QDebug>
-
-#include <wayland-server-protocol.h>
-#include "qwaylandsharedmemoryformathelper_p.h"
-
-#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QtWayland {
-
-SurfaceBuffer::SurfaceBuffer(QWaylandSurface *surface)
- : m_surface(surface)
- , m_compositor(surface->compositor())
- , m_buffer(0)
- , m_committed(false)
- , m_is_registered_for_buffer(false)
- , m_surface_has_buffer(false)
- , m_destroyed(false)
- , m_is_displayed(false)
- , m_used(false)
- , m_destroyIfUnused(false)
-{
-}
-
-SurfaceBuffer::~SurfaceBuffer()
-{
- if (m_is_registered_for_buffer)
- destructBufferState();
-}
-
-void SurfaceBuffer::initialize(struct ::wl_resource *buffer)
-{
- m_buffer = buffer;
- m_committed = false;
- m_is_registered_for_buffer = true;
- m_surface_has_buffer = true;
- m_is_displayed = false;
- m_destroyed = false;
- m_destroy_listener.surfaceBuffer = this;
- m_destroy_listener.listener.notify = destroy_listener_callback;
- if (buffer) {
-#ifdef QT_WAYLAND_COMPOSITOR_GL
- if (ClientBufferIntegration *integration = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration())
- integration->initializeBuffer(buffer);
-#endif
- wl_signal_add(&buffer->destroy_signal, &m_destroy_listener.listener);
- }
-}
-
-void SurfaceBuffer::destructBufferState()
-{
- if (m_buffer) {
- if (m_committed)
- sendRelease();
- wl_list_remove(&m_destroy_listener.listener.link);
- }
- m_buffer = 0;
- m_committed = false;
- m_is_registered_for_buffer = false;
- m_is_displayed = false;
-}
-
-void SurfaceBuffer::sendRelease()
-{
- Q_ASSERT(m_buffer);
- wl_buffer_send_release(m_buffer);
-}
-
-void SurfaceBuffer::disown()
-{
- m_surface_has_buffer = false;
- destructBufferState();
- destroyIfUnused();
-}
-
-void SurfaceBuffer::setDisplayed()
-{
- m_is_displayed = true;
-}
-
-void SurfaceBuffer::destroy_listener_callback(wl_listener *listener, void *data)
-{
- Q_UNUSED(data);
- struct surface_buffer_destroy_listener *destroy_listener =
- reinterpret_cast<struct surface_buffer_destroy_listener *>(listener);
- SurfaceBuffer *d = destroy_listener->surfaceBuffer;
-
- // Mark the buffer as destroyed and clear m_buffer right away to avoid
- // touching it before it is properly cleaned up.
- d->m_destroyed = true;
- d->m_buffer = 0;
-}
-
-void SurfaceBuffer::ref()
-{
- m_used = m_refCount.ref();
-}
-
-void SurfaceBuffer::deref()
-{
- m_used = m_refCount.deref();
- if (!m_used)
- disown();
-}
-
-void SurfaceBuffer::setDestroyIfUnused(bool destroy)
-{
- m_destroyIfUnused = destroy;
- destroyIfUnused();
-}
-
-void SurfaceBuffer::destroyIfUnused()
-{
- if (!m_used && m_destroyIfUnused)
- delete this;
-}
-
-QSize SurfaceBuffer::size() const
-{
- if (!m_buffer)
- return QSize();
-
- if (wl_shm_buffer *shmBuffer = wl_shm_buffer_get(m_buffer)) {
- int width = wl_shm_buffer_get_width(shmBuffer);
- int height = wl_shm_buffer_get_height(shmBuffer);
- return QSize(width, height);
- }
-#ifdef QT_WAYLAND_COMPOSITOR_GL
- if (ClientBufferIntegration *integration = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration()) {
- return integration->bufferSize(m_buffer);
- }
-#endif
-
- return QSize();
-}
-
-QWaylandSurface::Origin SurfaceBuffer::origin() const
-{
- if (isSharedMemory()) {
- return QWaylandSurface::OriginTopLeft;
- }
-
-#ifdef QT_WAYLAND_COMPOSITOR_GL
- if (ClientBufferIntegration *integration = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration()) {
- return integration->origin(m_buffer);
- }
-#endif
- return QWaylandSurface::OriginTopLeft;
-}
-
-QImage SurfaceBuffer::image() const
-{
- if (wl_shm_buffer *shmBuffer = wl_shm_buffer_get(m_buffer)) {
- int width = wl_shm_buffer_get_width(shmBuffer);
- int height = wl_shm_buffer_get_height(shmBuffer);
- int bytesPerLine = wl_shm_buffer_get_stride(shmBuffer);
- uchar *data = static_cast<uchar *>(wl_shm_buffer_get_data(shmBuffer));
- return QImage(data, width, height, bytesPerLine, QImage::Format_ARGB32_Premultiplied);
- }
-
- return QImage();
-}
-
-QWaylandBufferRef::BufferFormatEgl SurfaceBuffer::bufferFormatEgl() const
-{
- Q_ASSERT(isSharedMemory() == false);
-
-#ifdef QT_WAYLAND_COMPOSITOR_GL
- if (QtWayland::ClientBufferIntegration *clientInt = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration())
- return clientInt->bufferFormat(m_buffer);
-#endif
-
- return QWaylandBufferRef::BufferFormatEgl_Null;
-}
-
-#ifdef QT_WAYLAND_COMPOSITOR_GL
-void SurfaceBuffer::bindToTexture() const
-{
- Q_ASSERT(m_compositor);
- if (isSharedMemory()) {
- QImage image = this->image();
- if (image.hasAlphaChannel()) {
- if (image.format() != QImage::Format_RGBA8888) {
- image = image.convertToFormat(QImage::Format_RGBA8888);
- }
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.constBits());
- } else {
- if (image.format() != QImage::Format_RGBX8888) {
- image = image.convertToFormat(QImage::Format_RGBX8888);
- }
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, image.constBits());
- }
- } else {
- if (QtWayland::ClientBufferIntegration *clientInt = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration()) {
- clientInt->bindTextureToBuffer(m_buffer);
- }
- }
-}
-
-uint SurfaceBuffer::textureForPlane(int plane) const
-{
- if (QtWayland::ClientBufferIntegration *clientInt = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration())
- return clientInt->textureForBuffer(m_buffer, plane);
-
- return 0;
-}
-
-void SurfaceBuffer::updateTexture() const
-{
- if (QtWayland::ClientBufferIntegration *clientInt = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration())
- clientInt->updateTextureForBuffer(m_buffer);
-}
-#endif
-
-}
-
-QT_END_NAMESPACE
diff --git a/src/compositor/wayland_wrapper/wayland_wrapper.pri b/src/compositor/wayland_wrapper/wayland_wrapper.pri
index f338ddc05..fa5d76291 100644
--- a/src/compositor/wayland_wrapper/wayland_wrapper.pri
+++ b/src/compositor/wayland_wrapper/wayland_wrapper.pri
@@ -3,21 +3,23 @@ WAYLANDSERVERSOURCES += \
../3rdparty/protocol/wayland.xml \
HEADERS += \
+ wayland_wrapper/qwlbuffermanager_p.h \
+ wayland_wrapper/qwlclientbuffer_p.h \
wayland_wrapper/qwldatadevice_p.h \
wayland_wrapper/qwldatadevicemanager_p.h \
wayland_wrapper/qwldataoffer_p.h \
wayland_wrapper/qwldatasource_p.h \
wayland_wrapper/qwlregion_p.h \
- wayland_wrapper/qwlsurfacebuffer_p.h \
../shared/qwaylandxkb_p.h \
SOURCES += \
+ wayland_wrapper/qwlbuffermanager.cpp \
+ wayland_wrapper/qwlclientbuffer.cpp \
wayland_wrapper/qwldatadevice.cpp \
wayland_wrapper/qwldatadevicemanager.cpp \
wayland_wrapper/qwldataoffer.cpp \
wayland_wrapper/qwldatasource.cpp \
wayland_wrapper/qwlregion.cpp \
- wayland_wrapper/qwlsurfacebuffer.cpp \
../shared/qwaylandxkb.cpp \
INCLUDEPATH += wayland_wrapper
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