diff options
author | Gunnar Sletta <gunnar.sletta@jollamobile.com> | 2014-08-07 10:42:06 +0000 |
---|---|---|
committer | Gunnar Sletta <gunnar.sletta@jollamobile.com> | 2014-08-08 13:34:03 +0200 |
commit | cc4d473fff90f269bc3b16ea74db31747d8a3f3c (patch) | |
tree | 16dea850f9ff1a8f7f03b7c3d519a6d396334019 | |
parent | 21ab7593b96d4e867408364949a874b6bddebca2 (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.cpp | 37 | ||||
-rw-r--r-- | customcontext/context.h | 8 | ||||
-rw-r--r-- | customcontext/customcontext.pro | 11 | ||||
-rw-r--r-- | customcontext/texture/hybristexture.cpp | 404 | ||||
-rw-r--r-- | customcontext/texture/hybristexture.h | 118 |
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 |