summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@jollamobile.com>2014-08-07 10:42:06 +0000
committerGunnar Sletta <gunnar.sletta@jollamobile.com>2014-08-08 13:34:03 +0200
commitcc4d473fff90f269bc3b16ea74db31747d8a3f3c (patch)
tree16dea850f9ff1a8f7f03b7c3d519a6d396334019
parent21ab7593b96d4e867408364949a874b6bddebca2 (diff)
Introducing texture support based on EGL_HYBRIS_native_buffer.
This is the equivalent of eglgralloctexture, except it uses an EGL extension and will for that reason only depend on libEGL and not Android's libhardare and SDK. Change-Id: Ib06d56d62566bfe77a55690f51139d395540f254 Reviewed-by: Giulio Camuffo <giulio.camuffo@jollamobile.com> Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
-rw-r--r--customcontext/context.cpp37
-rw-r--r--customcontext/context.h8
-rw-r--r--customcontext/customcontext.pro11
-rw-r--r--customcontext/texture/hybristexture.cpp404
-rw-r--r--customcontext/texture/hybristexture.h118
5 files changed, 578 insertions, 0 deletions
diff --git a/customcontext/context.cpp b/customcontext/context.cpp
index 155bf54..aeffd41 100644
--- a/customcontext/context.cpp
+++ b/customcontext/context.cpp
@@ -80,6 +80,10 @@
#include "eglgralloctexture.h"
#endif
+#ifdef CUSTOMCONTEXT_HYBRISTEXTURE
+#include "hybristexture.h"
+#endif
+
#ifdef CUSTOMCONTEXT_MSAA
#include <private/qsgdefaultimagenode_p.h>
#include <private/qsgdefaultrectanglenode_p.h>
@@ -188,6 +192,14 @@ Context::Context(QObject *parent)
m_eglGrallocTexture = qEnvironmentVariableIsEmpty("CUSTOMCONTEXT_NO_EGLGRALLOCTEXTURE");
#endif
+#ifdef CUSTOMCONTEXT_HYBRISTEXTURE
+ m_hybrisTexture = qEnvironmentVariableIsEmpty("CUSTOMCONTEXT_NO_HYBRISTEXTURE");
+ if (m_hybrisTexture && strstr(eglQueryString(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_EXTENSIONS), "EGL_HYBRIS_native_buffer") == 0) {
+ qDebug() << "EGL_HYBRIS_native_buffer is not available...";
+ m_hybrisTexture = false;
+ }
+#endif
+
#ifdef CUSTOMCONTEXT_THREADUPLOADTEXTURE
m_threadUploadTexture = qgetenv("CUSTOMCONTEXT_NO_THREADUPLOADTEXTURE").isEmpty();
connect(this, SIGNAL(invalidated()), &m_threadUploadManager, SLOT(invalidated()), Qt::DirectConnection);
@@ -242,6 +254,9 @@ Context::Context(QObject *parent)
#ifdef CUSTOMCONTEXT_EGLGRALLOCTEXTURE
qDebug(" - EGLImage/Gralloc based texture: %s", m_eglGrallocTexture ? "yes" : "no");
#endif
+#ifdef CUSTOMCONTEXT_HYBRISTEXTURE
+ qDebug(" - EGL/Hybris based texture: %s", m_hybrisTexture ? "yes" : "no");
+#endif
#ifdef CUSTOMCONTEXT_MACTEXTURE
qDebug(" - mac textures: %s", m_macTexture ? "yes" : "no");
#endif
@@ -440,6 +455,20 @@ QSGTexture *RenderContext::createTextureNoAtlas(const QImage &image) const
}
}
#endif
+#ifdef CUSTOMCONTEXT_HYBRISTEXTURE
+ if (static_cast<Context *>(sceneGraphContext())->hasHybrisTextures()) {
+
+ // Only use hybris textures for textures created outside the render thread.
+ // They can still block for as long as normal texture, so better to not waste
+ // the precious resource.
+ if (openglContext() != 0 && openglContext()->thread() != QThread::currentThread()) {
+ HybrisTexture *t = HybrisTexture::create(image);
+ if (t)
+ return t;
+ }
+ }
+#endif
+
return CONTEXT_CLASS_BASE::createTextureNoAtlas(image);
}
#endif
@@ -481,6 +510,14 @@ QQuickTextureFactory *Context::createTextureFactory(const QImage &image)
{
Q_UNUSED(image);
+#ifdef CUSTOMCONTEXT_HYBRISTEXTURE
+ if (m_hybrisTexture) {
+ HybrisTextureFactory *tf = HybrisTextureFactory::create(image);
+ if (tf)
+ return tf;
+ }
+#endif
+
#ifdef CUSTOMCONTEXT_EGLGRALLOCTEXTURE
if (m_eglGrallocTexture) {
EglGrallocTextureFactory *tf = EglGrallocTextureFactory::create(image);
diff --git a/customcontext/context.h b/customcontext/context.h
index 962bd6b..ab2b229 100644
--- a/customcontext/context.h
+++ b/customcontext/context.h
@@ -139,6 +139,10 @@ public:
bool hasEglGrallocTextures() const { return m_eglGrallocTexture; }
#endif
+#ifdef CUSTOMCONTEXT_HYBRISTEXTURE
+ bool hasHybrisTextures() const { return m_hybrisTexture; }
+#endif
+
private:
int m_sampleCount;
@@ -201,6 +205,10 @@ private:
bool m_eglGrallocTexture;
#endif
+#ifdef CUSTOMCONTEXT_HYBRISTEXTURE
+ bool m_hybrisTexture;
+#endif
+
};
} // namespace
diff --git a/customcontext/customcontext.pro b/customcontext/customcontext.pro
index 3301541..39c993d 100644
--- a/customcontext/customcontext.pro
+++ b/customcontext/customcontext.pro
@@ -90,6 +90,17 @@ eglgralloctexture:{
message("eglgralloctexure .........: no")
}
+hybristexture :{
+ message("hybristexture ............: yes")
+ DEFINES += CUSTOMCONTEXT_HYBRISTEXTURE
+ SOURCES += texture/hybristexture.cpp
+ HEADERS += texture/hybristexture.h
+ INCLUDEPATH += texture
+
+} else {
+ message("hybristexture ............: no")
+}
+
nonpreservedtexture:{
message("nonpreservedtexture ......: yes")
DEFINES += CUSTOMCONTEXT_NONPRESERVEDTEXTURE
diff --git a/customcontext/texture/hybristexture.cpp b/customcontext/texture/hybristexture.cpp
new file mode 100644
index 0000000..e830a1c
--- /dev/null
+++ b/customcontext/texture/hybristexture.cpp
@@ -0,0 +1,404 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Scenegraph Playground module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "hybristexture.h"
+
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QThread>
+#include <QtCore/QCoreApplication>
+#include <QtCore/qdebug.h>
+
+#include <QtGui/private/qdrawhelper_p.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#ifndef QSG_NO_RENDER_TIMING
+static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
+static QElapsedTimer qsg_renderer_timer;
+#endif
+
+// from hybris_nativebuffer.h in libhybris
+#define HYBRIS_USAGE_SW_READ_RARELY 0x00000002
+#define HYBRIS_USAGE_SW_WRITE_RARELY 0x00000020
+#define HYBRIS_USAGE_HW_TEXTURE 0x00000100
+#define HYBRIS_PIXEL_FORMAT_RGBA_8888 1
+#define HYBRIS_PIXEL_FORMAT_BGRA_8888 5
+
+#define EGL_NATIVE_BUFFER_HYBRIS 0x3140
+
+namespace CustomContext {
+
+extern "C" {
+ typedef EGLBoolean (EGLAPIENTRYP _eglHybrisCreateNativeBuffer)(EGLint width, EGLint height, EGLint usage, EGLint format, EGLint *stride, EGLClientBuffer *buffer);
+ typedef EGLBoolean (EGLAPIENTRYP _eglHybrisLockNativeBuffer)(EGLClientBuffer buffer, EGLint usage, EGLint l, EGLint t, EGLint w, EGLint h, void **vaddr);
+ typedef EGLBoolean (EGLAPIENTRYP _eglHybrisUnlockNativeBuffer)(EGLClientBuffer buffer);
+ typedef EGLBoolean (EGLAPIENTRYP _eglHybrisReleaseNativeBuffer)(EGLClientBuffer buffer);
+
+ typedef void (EGLAPIENTRYP _glEGLImageTargetTexture2DOES)(GLenum target, EGLImageKHR image);
+ typedef EGLImageKHR (EGLAPIENTRYP _eglCreateImageKHR)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attribs);
+ typedef EGLBoolean (EGLAPIENTRYP _eglDestroyImageKHR)(EGLDisplay dpy, EGLImageKHR image);
+}
+
+_glEGLImageTargetTexture2DOES glEGLImageTargetTexture2DOES = 0;
+_eglCreateImageKHR eglCreateImageKHR = 0;
+_eglDestroyImageKHR eglDestroyImageKHR = 0;
+
+_eglHybrisCreateNativeBuffer eglHybrisCreateNativeBuffer = 0;
+_eglHybrisLockNativeBuffer eglHybrisLockNativeBuffer = 0;
+_eglHybrisUnlockNativeBuffer eglHybrisUnlockNativeBuffer = 0;
+_eglHybrisReleaseNativeBuffer eglHybrisReleaseNativeBuffer = 0;
+
+static void initialize()
+{
+ glEGLImageTargetTexture2DOES = (_glEGLImageTargetTexture2DOES) eglGetProcAddress("glEGLImageTargetTexture2DOES");
+ eglCreateImageKHR = (_eglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR");
+ eglDestroyImageKHR = (_eglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR");
+ eglHybrisCreateNativeBuffer = (_eglHybrisCreateNativeBuffer) eglGetProcAddress("eglHybrisCreateNativeBuffer");
+ eglHybrisLockNativeBuffer = (_eglHybrisLockNativeBuffer) eglGetProcAddress("eglHybrisLockNativeBuffer");
+ eglHybrisUnlockNativeBuffer = (_eglHybrisUnlockNativeBuffer) eglGetProcAddress("eglHybrisUnlockNativeBuffer");
+ eglHybrisReleaseNativeBuffer = (_eglHybrisReleaseNativeBuffer) eglGetProcAddress("eglHybrisReleaseNativeBuffer");
+}
+
+NativeBuffer::NativeBuffer(const QImage &image)
+{
+ hasAlpha = image.hasAlphaChannel();
+ const QImage::Format iformat = image.format();
+ format = iformat == QImage::Format_RGBA8888_Premultiplied
+ || iformat == QImage::Format_RGBX8888
+ || iformat == QImage::Format_RGBA8888
+ ? HYBRIS_PIXEL_FORMAT_RGBA_8888
+ : HYBRIS_PIXEL_FORMAT_BGRA_8888;
+ int usage = HYBRIS_USAGE_SW_READ_RARELY | HYBRIS_USAGE_SW_WRITE_RARELY | HYBRIS_USAGE_HW_TEXTURE;
+ width = image.width();
+ height = image.height();
+ stride = 0;
+ buffer = 0;
+
+#ifdef CUSTOMCONTEXT_DEBUG
+ QElapsedTimer timer;
+ timer.start();
+#endif
+
+ char *data = 0;
+
+ EGLint status;
+
+ status = eglHybrisCreateNativeBuffer(width, height, usage, format, &stride, &buffer);
+ if (status != EGL_TRUE || !buffer) {
+ qDebug() << "eglHybrisCreateNativeBuffer failed, error:" << hex << eglGetError();
+ return;
+ }
+
+#ifdef CUSTOMCONTEXT_DEBUG
+ quint64 allocTime = timer.elapsed();
+#endif
+
+ status = eglHybrisLockNativeBuffer(buffer, HYBRIS_USAGE_SW_WRITE_RARELY, 0, 0, width, height, (void **) &data);
+ if (status != EGL_TRUE || data == 0) {
+ qDebug() << "eglHybrisLockNativeBuffer failed, error:" << hex << eglGetError();
+ release();
+ return;
+ }
+
+#ifdef CUSTOMCONTEXT_DEBUG
+ quint64 lockTime = timer.elapsed();
+#endif
+
+ bool simpleCopy = iformat == QImage::Format_ARGB32_Premultiplied
+ || iformat == QImage::Format_RGB32
+ || iformat == QImage::Format_RGBA8888_Premultiplied
+ || iformat == QImage::Format_RGBX8888;
+
+ const int dbpl = stride * 4;
+ const int h = image.height();
+ const int w = image.width();
+ if (simpleCopy) {
+ if (dbpl == image.bytesPerLine()) {
+ memcpy(data, image.constBits(), image.byteCount());
+ } else {
+ int bpl = qMin(dbpl, image.bytesPerLine());
+ for (int y=0; y<h; ++y)
+ memcpy(data + y * dbpl, image.constScanLine(y), bpl);
+ }
+ } else {
+ if (iformat == QImage::Format_ARGB32) {
+ for (int y=0; y<h; ++y) {
+ const uint *src = (const uint *) image.constScanLine(y);
+ uint *dst = (uint *) (data + dbpl * y);
+ for (int x=0; x<w; ++x)
+ dst[x] = PREMUL(src[x]);
+ }
+ } else { // QImage::Format_RGBA88888 (non-premultiplied)
+ for (int y=0; y<h; ++y) {
+ const uchar *src = image.constScanLine(y);
+ uchar *dst = (uchar *) (data + dbpl * y);
+ for (int x=0; x<w; ++x) {
+ int p = x<<2;
+ uint a = src[p + 3];
+ dst[p ] = qt_div_255(src[p ] * a);
+ dst[p+1] = qt_div_255(src[p+1] * a);
+ dst[p+2] = qt_div_255(src[p+2] * a);
+ dst[p+3] = a;
+ }
+ }
+ }
+ }
+
+#ifdef CUSTOMCONTEXT_DEBUG
+ quint64 copyTime = timer.elapsed();
+#endif
+
+ if (!eglHybrisUnlockNativeBuffer(buffer)) {
+ qDebug() << "eglHybrisUnlockNativeBuffer failed, error:" << hex << eglGetError();
+ release();
+ return;
+ }
+
+#ifdef CUSTOMCONTEXT_DEBUG
+ quint64 unlockTime = timer.elapsed();
+#endif
+
+ eglImage = eglCreateImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY),
+ EGL_NO_CONTEXT,
+ EGL_NATIVE_BUFFER_HYBRIS,
+ buffer,
+ 0);
+
+ if (!eglImage) {
+ qDebug() << "eglCreateImageKHR failed, error:" << hex << eglGetError();
+ release();
+ return;
+ }
+
+#ifdef CUSTOMCONTEXT_DEBUG
+ quint64 imageTime = timer.elapsed();
+#endif
+
+#ifdef CUSTOMCONTEXT_DEBUG
+ qDebug("HybrisTexture: created buffer: %d x %d, buffer=%p, stride=%d/%d (%d), time: alloc=%d, lock=%d, copy=%d, unlock=%d, eglImage=%d",
+ width, height,
+ buffer,
+ stride, stride * 4, image.bytesPerLine(),
+ (int) allocTime,
+ (int) (lockTime - allocTime),
+ (int) (copyTime - lockTime),
+ (int) (unlockTime - copyTime),
+ (int) (imageTime - unlockTime));
+#endif
+}
+
+NativeBuffer::~NativeBuffer()
+{
+#ifdef CUSTOMCONTEXT_DEBUG
+ qDebug() << "HybrisTexture: native buffer released.." << (void *) this;
+#endif
+ release();
+}
+
+void NativeBuffer::release()
+{
+ if (eglImage) {
+ eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), eglImage);
+ eglImage = 0;
+ }
+ if (buffer) {
+ eglHybrisReleaseNativeBuffer(buffer);
+ buffer = 0;
+ }
+}
+
+NativeBuffer *NativeBuffer::create(const QImage &image)
+{
+ if (image.width() * image.height() < 500 * 500 || image.depth() != 32)
+ return 0;
+
+ if (!eglHybrisCreateNativeBuffer) {
+ initialize();
+ if (!eglHybrisCreateNativeBuffer)
+ return 0;
+ }
+
+ NativeBuffer *buffer = new NativeBuffer(image);
+ if (buffer && !buffer->buffer) {
+#ifdef CUSTOMCONTEXT_DEBUG
+ qDebug("HybrisTexture: failed to allocate native buffer for image: %d x %d", image.width(), image.height());
+#endif
+ delete buffer;
+ return 0;
+ }
+
+ return buffer;
+}
+
+HybrisTexture::HybrisTexture(NativeBuffer *buffer)
+ : m_id(0)
+ , m_buffer(buffer)
+ , m_bound(false)
+ , m_ownsBuffer(false)
+{
+ Q_ASSERT(buffer);
+#ifdef CUSTOMCONTEXT_DEBUG
+ qDebug() << "HybrisTexture: created" << QSize(buffer->width, buffer->height) << buffer << (void *) (buffer ? buffer->eglImage : 0) << (void *) (buffer ? buffer->buffer : 0);
+#endif
+}
+
+HybrisTexture::~HybrisTexture()
+{
+ if (m_id)
+ glDeleteTextures(1, &m_id);
+ if (m_ownsBuffer)
+ delete m_buffer;
+}
+
+void HybrisTexture::bind()
+{
+ glBindTexture(GL_TEXTURE_2D, textureId());
+ updateBindOptions(!m_bound);
+
+ if (!m_bound) {
+ m_bound = true;
+
+#ifdef CUSTOMCONTEXT_DEBUG
+ qsg_render_timing = true;
+#endif
+ if (Q_UNLIKELY(qsg_render_timing))
+ qsg_renderer_timer.start();
+
+ while (glGetError() != GL_NO_ERROR); // Clear pending errors
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_buffer->eglImage);
+
+ int error;
+ while ((error = glGetError()) != GL_NO_ERROR)
+ qDebug() << "Error after glEGLImageTargetTexture2DOES" << hex << error;
+
+ if (Q_UNLIKELY(qsg_render_timing))
+ qDebug(" - Hybristexture(%dx%d) bind=%d ms", m_buffer->width, m_buffer->height, (int) qsg_renderer_timer.elapsed());
+ }
+}
+
+int HybrisTexture::textureId() const
+{
+ if (m_id == 0)
+ glGenTextures(1, &m_id);
+ return m_id;
+}
+
+QSize HybrisTexture::textureSize() const
+{
+ return QSize(m_buffer->width, m_buffer->height);
+}
+
+bool HybrisTexture::hasAlphaChannel() const
+{
+ return m_buffer->hasAlpha;
+}
+
+bool HybrisTexture::hasMipmaps() const
+{
+ return false;
+}
+
+HybrisTexture *HybrisTexture::create(const QImage &image)
+{
+ NativeBuffer *buffer = NativeBuffer::create(image);
+ if (!buffer)
+ return 0;
+ HybrisTexture *texture = new HybrisTexture(buffer);
+ texture->m_ownsBuffer = true;
+ return texture;
+}
+
+HybrisTextureFactory::HybrisTextureFactory(NativeBuffer *buffer)
+ : m_buffer(buffer)
+{
+#ifdef CUSTOMCONTEXT_DEBUG
+ qDebug("HybrisTexture: creating texture factory size=%dx%d, buffer=%p", buffer->width, buffer->height, buffer);
+#endif
+}
+
+HybrisTextureFactory::~HybrisTextureFactory()
+{
+ delete m_buffer;
+}
+
+QSGTexture *HybrisTextureFactory::createTexture(QQuickWindow *) const
+{
+ return new HybrisTexture(m_buffer);
+}
+
+QSize HybrisTextureFactory::textureSize() const
+{
+ return QSize(m_buffer->width, m_buffer->height);
+}
+
+int HybrisTextureFactory::textureByteCount() const
+{
+ return m_buffer->stride * m_buffer->height;
+}
+
+QImage HybrisTextureFactory::image() const
+{
+ void *data = 0;
+ if (!eglHybrisLockNativeBuffer(m_buffer->buffer, HYBRIS_USAGE_SW_READ_RARELY, 0, 0, m_buffer->width, m_buffer->height, (void **) &data) || data == 0) {
+ qDebug() << "HybrisTextureFactory::image(): lock failed, cannot get image data; error:" << hex << eglGetError();
+ return QImage();
+ }
+
+ QImage content = QImage((const uchar *) data, m_buffer->width, m_buffer->height, m_buffer->stride * 4,
+ m_buffer->hasAlpha ? QImage::Format_ARGB32_Premultiplied
+ : QImage::Format_RGB32).copy();
+
+ if (!eglHybrisUnlockNativeBuffer(m_buffer->buffer)) {
+ qDebug() << "HybrisTextureFactory::image(): unlock failed; error:" << hex << eglGetError();
+ return QImage();
+ }
+
+ return content;
+}
+
+HybrisTextureFactory *HybrisTextureFactory::create(const QImage &image)
+{
+ NativeBuffer *buffer = NativeBuffer::create(image);
+ return buffer ? new HybrisTextureFactory(buffer) : 0;
+}
+
+}
diff --git a/customcontext/texture/hybristexture.h b/customcontext/texture/hybristexture.h
new file mode 100644
index 0000000..31018e9
--- /dev/null
+++ b/customcontext/texture/hybristexture.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Scenegraph Playground module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef HYBRISTEXTURE_H
+#define HYBRISTEXTURE_H
+
+#include <QtQuick/QSGTexture>
+#include <QtQuick/QQuickTextureFactory>
+
+#include <QtGui/qopengl.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+class QQuickWindow;
+
+namespace CustomContext {
+
+class NativeBuffer
+{
+public:
+ NativeBuffer(const QImage &image);
+ ~NativeBuffer();
+
+ static NativeBuffer *create(const QImage &image);
+
+ void release();
+
+ EGLClientBuffer buffer;
+ EGLImageKHR eglImage;
+ int width;
+ int height;
+ int stride;
+ int format;
+ bool hasAlpha;
+};
+
+class HybrisTexture : public QSGTexture
+{
+ Q_OBJECT
+public:
+ HybrisTexture(NativeBuffer *buffer);
+ ~HybrisTexture();
+
+ virtual int textureId() const;
+ virtual QSize textureSize() const;
+ virtual bool hasAlphaChannel() const;
+ virtual bool hasMipmaps() const;
+ virtual void bind();
+
+ static HybrisTexture *create(const QImage &image);
+
+private:
+ mutable GLuint m_id;
+ NativeBuffer *m_buffer;
+ bool m_bound;
+ bool m_ownsBuffer;
+};
+
+class HybrisTextureFactory : public QQuickTextureFactory
+{
+ Q_OBJECT
+public:
+ HybrisTextureFactory(NativeBuffer *buffer);
+ ~HybrisTextureFactory();
+
+ virtual QSGTexture *createTexture(QQuickWindow *window) const;
+ virtual QSize textureSize() const;
+ virtual int textureByteCount() const;
+ virtual QImage image() const;
+
+ static HybrisTextureFactory *create(const QImage &image);
+
+private:
+ NativeBuffer *m_buffer;
+};
+
+}
+
+#endif // HYBRISTEXTURE_H