diff options
author | Rhys Weatherley <rhys.weatherley@nokia.com> | 2010-04-03 08:51:07 +1000 |
---|---|---|
committer | Rhys Weatherley <rhys.weatherley@nokia.com> | 2010-04-03 09:25:40 +1000 |
commit | 4606fd8abf865919b94d5645a2051dc9c92e2b09 (patch) | |
tree | 7a7df15680741486d10f8a146478bc7154bbba77 /src/openclgl | |
parent | 5ee66bb5c79ad8e0d065bb75d4263a51253a60b3 (diff) |
Split the OpenGL dependencies out into a separate library.
Eventually we may want to put QtOpenCL into QtGui, so we cannot
have any OpenGL dependencies in it.
Diffstat (limited to 'src/openclgl')
-rw-r--r-- | src/openclgl/openclgl.pro | 47 | ||||
-rw-r--r-- | src/openclgl/openclgl_dep.pri | 21 | ||||
-rw-r--r-- | src/openclgl/qcl_gl_p.h | 73 | ||||
-rw-r--r-- | src/openclgl/qcl_glproxy_p.h | 77 | ||||
-rw-r--r-- | src/openclgl/qclcontextgl.cpp | 722 | ||||
-rw-r--r-- | src/openclgl/qclcontextgl.h | 128 | ||||
-rw-r--r-- | src/openclgl/qcltexture2d.cpp | 337 | ||||
-rw-r--r-- | src/openclgl/qcltexture2d.h | 90 |
8 files changed, 1495 insertions, 0 deletions
diff --git a/src/openclgl/openclgl.pro b/src/openclgl/openclgl.pro new file mode 100644 index 0000000..2c503b0 --- /dev/null +++ b/src/openclgl/openclgl.pro @@ -0,0 +1,47 @@ +TEMPLATE = lib +TARGET = QtOpenCLGL +QT += opengl +CONFIG += dll \ + warn_on +win32 { + DESTDIR = ../../bin + !static:DEFINES += QT_MAKEDLL +} +else:DESTDIR = ../../lib + +macx { + LIBS += -framework OpenCL +} else { + !isEmpty(QMAKE_INCDIR_OPENCL) { + QMAKE_CXXFLAGS += -I$$QMAKE_INCDIR_OPENCL + } + !isEmpty(QMAKE_LIBDIR_OPENCL) { + LIBS += -L$$QMAKE_LIBDIR_OPENCL + } + !isEmpty(QMAKE_LIBS_OPENCL) { + LIBS += $$QMAKE_LIBS_OPENCL + } else { + LIBS += -lOpenCL + } +} + +no_cl_gl { + DEFINES += QT_NO_CL_OPENGL +} + +INCLUDEPATH += $$PWD/../opencl + +HEADERS += \ + qclcontextgl.h \ + qcltexture2d.h + +SOURCES += \ + qclcontextgl.cpp \ + qcltexture2d.cpp + +PRIVATE_HEADERS += \ + qcl_gl_p.h \ + qcl_glproxy_p.h + +HEADERS += $$PRIVATE_HEADERS +DEFINES += QT_BUILD_CLGL_LIB diff --git a/src/openclgl/openclgl_dep.pri b/src/openclgl/openclgl_dep.pri new file mode 100644 index 0000000..d8e8906 --- /dev/null +++ b/src/openclgl/openclgl_dep.pri @@ -0,0 +1,21 @@ +INCLUDEPATH += $$PWD $$PWD/../opencl +macx { + LIBS += -lQtOpenCLGL -lQtOpenCL -framework OpenCL +} else { + LIBS += -lQtOpenCLGL -lQtOpenCL + !isEmpty(QMAKE_INCDIR_OPENCL) { + QMAKE_CXXFLAGS += -I$$QMAKE_INCDIR_OPENCL + } + !isEmpty(QMAKE_LIBDIR_OPENCL) { + LIBS += -L$$QMAKE_LIBDIR_OPENCL + } + !isEmpty(QMAKE_LIBS_OPENCL) { + LIBS += $$QMAKE_LIBS_OPENCL + } else { + LIBS += -lOpenCL + } +} +QT += opengl +no_cl_gl { + DEFINES += QT_NO_CL_OPENGL +} diff --git a/src/openclgl/qcl_gl_p.h b/src/openclgl/qcl_gl_p.h new file mode 100644 index 0000000..361b893 --- /dev/null +++ b/src/openclgl/qcl_gl_p.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenCL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCL_GL_P_H +#define QCL_GL_P_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. +// + +#if !defined(QT_NO_CL_OPENGL) + +#include <QtOpenGL/qgl.h> +#if defined(__APPLE__) || defined(__MACOSX) +#include <OpenGL/OpenGL.h> +#include <OpenCL/cl_platform.h> +#include <OpenCL/cl.h> +#include <OpenCL/cl_gl.h> +#include <CGLDevice.h> +#else +#include <CL/cl_platform.h> +#include <CL/cl.h> +#include <CL/cl_gl.h> +#endif + +#endif + +#endif diff --git a/src/openclgl/qcl_glproxy_p.h b/src/openclgl/qcl_glproxy_p.h new file mode 100644 index 0000000..5dbc4fb --- /dev/null +++ b/src/openclgl/qcl_glproxy_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenCL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCL_GLPROXY_P_H +#define QCL_GLPROXY_P_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 <QtOpenGL/qgl.h> + +QT_BEGIN_NAMESPACE + +// Copied from <QtOpenGL/private/qgl_p.h>. Hopefully won't be +// necessary in future versions of Qt. +class Q_OPENGL_EXPORT QGLSignalProxy : public QObject +{ + Q_OBJECT +public: + QGLSignalProxy() : QObject() {} + void emitAboutToDestroyContext(const QGLContext *context) { + emit aboutToDestroyContext(context); + } + static QGLSignalProxy *instance(); +Q_SIGNALS: + void aboutToDestroyContext(const QGLContext *context); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/openclgl/qclcontextgl.cpp b/src/openclgl/qclcontextgl.cpp new file mode 100644 index 0000000..58b3da2 --- /dev/null +++ b/src/openclgl/qclcontextgl.cpp @@ -0,0 +1,722 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenCL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qclcontextgl.h" +#include "qcl_gl_p.h" +#include <QtCore/qdebug.h> +#include <QtCore/qvarlengtharray.h> + +#if !defined(QT_NO_CL_OPENGL) +#if defined(QT_OPENGL_ES_2) +#include <EGL/egl.h> +#elif defined(QT_OPENGL_ES) +#include <GLES/egl.h> +#elif defined(Q_WS_X11) +#include <GL/glx.h> +#endif +#endif + +QT_BEGIN_NAMESPACE + +/*! + \class QCLContextGL + \brief The QCLContextGL class represents an OpenCL context that is suitable for use with OpenGL objects. + \since 4.7 + \ingroup opencl +*/ + +class QCLContextGLPrivate +{ +public: + QCLContextGLPrivate() + : supportsSharing(false) + { + } + + bool supportsSharing; +}; + +/*! + Constructs a new OpenCL context object that is suitable for use + with OpenGL objects. +*/ +QCLContextGL::QCLContextGL() + : QCLContext(), d_ptr(new QCLContextGLPrivate()) +{ +} + +/*! + Destroys this OpenCL context. +*/ +QCLContextGL::~QCLContextGL() +{ +} + +extern "C" { + +static void qt_clgl_context_notify(const char *errinfo, + const void *private_info, + size_t cb, + void *user_data) +{ + Q_UNUSED(private_info); + Q_UNUSED(cb); + Q_UNUSED(user_data); + qWarning() << "OpenCL/GL context notification: " << errinfo; +} + +}; + +#define CL_GL_CONTEXT_KHR 0x2008 +#define CL_EGL_DISPLAY_KHR 0x2009 +#define CL_GLX_DISPLAY_KHR 0x200A +#define CL_WGL_HDC_KHR 0x200B +#define CL_CGL_SHAREGROUP_KHR 0x200C + +/*! + Creates an OpenCL context that is compatible with the current + QGLContext. Returns false if there is no OpenGL context current or + the OpenCL context could not be created for some reason. + + This function will first try to create a QCLDevice::GPU device, + and will then fall back to QCLDevice::Default if a GPU is not found. + + \sa supportsObjectSharing() +*/ +bool QCLContextGL::create() +{ + Q_D(QCLContextGL); + + // Bail out if the context already exists. + if (isCreated()) + return true; + + // Bail out if we don't have an OpenGL context. + if (!QGLContext::currentContext()) { + qWarning() << "QCLContextGL::create: needs a current GL context"; + setLastError(CL_INVALID_CONTEXT); + return false; + } + + // Find the first gpu device. + QCLPlatform plat = platform(); + QList<QCLDevice> devices; + cl_device_type deviceType = CL_DEVICE_TYPE_GPU; + if (plat.isNull()) { + devices = QCLDevice::devices(QCLDevice::GPU); + if (devices.isEmpty()) { + devices = QCLDevice::devices(QCLDevice::Default); + deviceType = CL_DEVICE_TYPE_DEFAULT; + } + } else { + devices = QCLDevice::devices(QCLDevice::GPU, plat); + if (devices.isEmpty()) { + devices = QCLDevice::devices(QCLDevice::Default, plat); + deviceType = CL_DEVICE_TYPE_DEFAULT; + } + } + if (devices.isEmpty()) { + qWarning() << "QCLContextGL::create: no gpu devices found"; + setLastError(CL_DEVICE_NOT_FOUND); + return false; + } + QCLDevice gpu = devices[0]; + + // Add the platform identifier to the properties, if present. + QVarLengthArray<cl_context_properties> properties; + if (!plat.isNull()) { + properties.append(CL_CONTEXT_PLATFORM); + properties.append(cl_context_properties(plat.platformId())); + } + + bool hasSharing = false; +#ifndef QT_NO_CL_OPENGL + // Determine what kind of OpenCL-OpenGL sharing we have and enable it. + QStringList extensions = gpu.extensions(); +#if defined(__APPLE__) || defined(__MACOSX) + bool appleSharing = gpu.hasExtension("cl_apple_gl_sharing"); + if (appleSharing) { + CGLContextObj cglContext = CGLGetCurrentContext(); + CGLShareGroupObj cglShareGroup = CGLGetShareGroup(cglContext); + properties.append(CL_CGL_SHAREGROUP_KHR); + properties.append(cl_context_properties(cglShareGroup)); + hasSharing = true; + } +#else + bool khrSharing = gpu.hasExtension("cl_khr_gl_sharing"); +#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_ES) + if (khrSharing) { + properties.append(CL_EGL_DISPLAY_KHR); + properties.append(cl_context_properties(eglGetCurrentDisplay())); +#ifdef EGL_OPENGL_ES_API + eglBindAPI(EGL_OPENGL_ES_API); +#endif + properties.append(CL_GL_CONTEXT_KHR); + properties.append(cl_context_properties(eglGetCurrentContext())); + hasSharing = true; + } +#elif defined(Q_WS_X11) + if (khrSharing) { + properties.append(CL_GLX_DISPLAY_KHR); + properties.append(cl_context_properties(glXGetCurrentDisplay())); + properties.append(CL_GL_CONTEXT_KHR); + properties.append(cl_context_properties(glXGetCurrentContext())); + hasSharing = true; + } +#else + // Needs to be ported to other platforms. + if (khrSharing) + qWarning() << "QCLContextGL::create: do not know how to enable sharing"; +#endif +#endif +#endif // !QT_NO_CL_OPENGL + + // Create the OpenCL context. + cl_context id; + cl_int error; + if (!properties.isEmpty()) { + id = clCreateContextFromType + (properties.data(), deviceType, + qt_clgl_context_notify, 0, &error); + } else { + id = clCreateContextFromType + (0, deviceType, qt_clgl_context_notify, 0, &error); + } + if (!id && error == CL_INVALID_PLATFORM && plat.isNull()) { + // Some OpenCL implementations seem to fail if a non-specific + // platform is supplied. Try again with an explicit device. + cl_device_id dev = gpu.deviceId(); + if (!properties.isEmpty()) { + id = clCreateContext + (properties.data(), 1, &dev, + qt_clgl_context_notify, 0, &error); + } + if (!id && error == CL_INVALID_VALUE) { + // One more try - remove the GL properties. + id = clCreateContext + (0, 1, &dev, qt_clgl_context_notify, 0, &error); + hasSharing = false; + } + } + setLastError(error); + if (id == 0) { + qWarning() << "QCLContextGL::create:" << errorName(error); + d->supportsSharing = false; + } else { + d->supportsSharing = hasSharing; + setContextId(id); + clReleaseContext(id); // setContextId() adds an extra reference. + } + return id != 0; +} + +/*! + Returns true if this OpenCL context supports object sharing + with OpenGL; false otherwise. + + \sa createGLBuffer(), createTexture2D(), createTexture3D() + \sa createRenderbuffer() +*/ +bool QCLContextGL::supportsObjectSharing() const +{ + Q_D(const QCLContextGL); + return d->supportsSharing; +} + +/*! + Creates an OpenCL memory buffer from the OpenGL buffer object + \a bufobj, with the specified \a access mode. + + This function will only work if supportsObjectSharing() is true. +*/ +QCLBuffer QCLContextGL::createGLBuffer(GLuint bufobj, QCL::Access access) +{ +#ifndef QT_NO_CL_OPENGL + cl_int error = CL_INVALID_CONTEXT; + cl_mem_flags flags = cl_mem_flags(access); + cl_mem mem = clCreateFromGLBuffer + (contextId(), flags, bufobj, &error); + reportError("QCLContextGL::createGLBuffer:", error); + if (mem) + return QCLBuffer(this, mem); + else + return QCLBuffer(); +#else + Q_UNUSED(bufobj); + Q_UNUSED(access); + reportError("QCLContextGL::createGLBuffer:", CL_INVALID_VALUE); + return QCLBuffer(); +#endif +} + +#if QT_VERSION >= 0x040700 || defined(Q_QDOC) + +/*! + \overload + + Creates an OpenCL memory buffer from the OpenGL buffer object + \a bufobj, with the specified \a access mode. + + This function will only work if supportsObjectSharing() is true. +*/ +QCLBuffer QCLContextGL::createGLBuffer(QGLBuffer *bufobj, QCL::Access access) +{ + if (!bufobj) + return QCLBuffer(); + return createGLBuffer(GLuint(bufobj->bufferId()), access); +} + +#endif + +/*! + Creates a 2D OpenCL image object from the specified \a mipmapLevel, + OpenGL \a texture object, and \a access mode. + + The \a type must be one of \c{GL_TEXTURE_2D}, + \c{GL_TEXTURE_CUBE_MAP_POSITIVE_X}, \c{GL_TEXTURE_CUBE_MAP_POSITIVE_Y}, + \c{GL_TEXTURE_CUBE_MAP_POSITIVE_Z}, \c{GL_TEXTURE_CUBE_MAP_NEGATIVE_X}, + \c{GL_TEXTURE_CUBE_MAP_NEGATIVE_Y}, \c{GL_TEXTURE_CUBE_MAP_NEGATIVE_Z}, + or \c{GL_TEXTURE_RECTANGLE}. The \a texture does not need to be + bound to an OpenGL texture target. + + This function will only work if supportsObjectSharing() is true. + + \sa createTexture3D(), createRenderbuffer() +*/ +QCLImage2D QCLContextGL::createTexture2D + (GLenum type, GLuint texture, GLint mipmapLevel, QCL::Access access) +{ +#ifndef QT_NO_CL_OPENGL + cl_int error = CL_INVALID_CONTEXT; + cl_mem_flags flags = cl_mem_flags(access); + cl_mem mem = clCreateFromGLTexture2D + (contextId(), flags, type, mipmapLevel, texture, &error); + reportError("QCLContextGL::createGLTexture2D:", error); + if (mem) + return QCLImage2D(this, mem); + else + return QCLImage2D(); +#else + Q_UNUSED(type); + Q_UNUSED(texture); + Q_UNUSED(mipmapLevel); + Q_UNUSED(access); + reportError("QCLContextGL::createGLTexture2D:", CL_INVALID_VALUE); + return QCLImage2D(); +#endif +} + +/*! + \overload + + Creates a 2D OpenCL image object from the specified OpenGL + \a texture object, and the \a access mode. If texture type is + assumed to be \c{GL_TEXTURE_2D} and the mipmap level is + assumed to be 0. + + This function will only work if supportsObjectSharing() is true. +*/ +QCLImage2D QCLContextGL::createTexture2D(GLuint texture, QCL::Access access) +{ + return createTexture2D(GL_TEXTURE_2D, texture, 0, access); +} + +#ifndef GL_TEXTURE_3D +#define GL_TEXTURE_3D 0x806F +#endif + +/*! + Creates a 3D OpenCL image object from the specified \a mipmapLevel, + OpenGL \a texture object, and \a access mode. + + The \a type must be \c{GL_TEXTURE_3D}. The \a texture does not need + to be bound to an OpenGL texture target. + + This function will only work if supportsObjectSharing() is true. + + \sa createTexture2D() +*/ +QCLImage3D QCLContextGL::createTexture3D + (GLenum type, GLuint texture, GLint mipmapLevel, QCL::Access access) +{ +#ifndef QT_NO_CL_OPENGL + cl_int error = CL_INVALID_CONTEXT; + cl_mem_flags flags = cl_mem_flags(access); + cl_mem mem = clCreateFromGLTexture3D + (contextId(), flags, type, mipmapLevel, texture, &error); + reportError("QCLContextGL::createGLTexture3D:", error); + if (mem) + return QCLImage3D(this, mem); + else + return QCLImage3D(); +#else + Q_UNUSED(type); + Q_UNUSED(texture); + Q_UNUSED(mipmapLevel); + Q_UNUSED(access); + reportError("QCLContextGL::createGLTexture3D:", CL_INVALID_VALUE); + return QCLImage3D(); +#endif +} + +/*! + \overload + + Creates a 3D OpenCL image object from the specified OpenGL + \a texture object, and \a access mode. If texture type is + assumed to be \c{GL_TEXTURE_3D} and the mipmap level is + assumed to be 0. + + This function will only work if supportsObjectSharing() is true. +*/ +QCLImage3D QCLContextGL::createTexture3D(GLuint texture, QCL::Access access) +{ + return createTexture3D(GL_TEXTURE_3D, texture, 0, access); +} + +/*! + Creates a 2D OpenCL image object from the specified OpenGL + \a renderbuffer object, and the \a access mode. + + This function will only work if supportsObjectSharing() is true. + + \sa createTexture2D() +*/ +QCLImage2D QCLContextGL::createRenderbuffer + (GLuint renderbuffer, QCL::Access access) +{ +#ifndef QT_NO_CL_OPENGL + cl_int error = CL_INVALID_CONTEXT; + cl_mem_flags flags = cl_mem_flags(access); + cl_mem mem = clCreateFromGLRenderbuffer + (contextId(), flags, renderbuffer, &error); + reportError("QCLContextGL::createGLRenderbuffer:", error); + if (mem) + return QCLImage2D(this, mem); + else + return QCLImage2D(); +#else + Q_UNUSED(renderbuffer); + Q_UNUSED(access); + reportError("QCLContextGL::createRenderbuffer:", CL_INVALID_VALUE); + return QCLImage2D(); +#endif +} + +/*! + \internal +*/ +void QCLContextGL::reportError(const char *name, cl_int error) +{ + setLastError(error); + if (error != CL_SUCCESS) + qWarning() << name << QCLContext::errorName(error); +} + +#ifdef Q_MAC_COMPAT_GL_FUNCTIONS + +/*! + \internal +*/ +QCLBuffer QCLContextGL::createGLBuffer + (QMacCompatGLuint bufobj, QCL::Access access) +{ + return createGLBuffer(GLuint(bufobj), access); +} + +/*! + \internal +*/ +QCLImage2D QCLContextGL::createTexture2D + (QMacCompatGLenum type, QMacCompatGLuint texture, + QMacCompatGLint mipmapLevel, QCL::Access access) +{ + return createTexture2D(GLenum(type), GLuint(texture), + GLint(mipmapLevel), access); +} + +/*! + \internal +*/ +QCLImage2D QCLContextGL::createTexture2D + (QMacCompatGLuint texture, QCL::Access access) +{ + return createTexture2D(GLenum(GL_TEXTURE_2D), GLuint(texture), + GLint(0), access); +} + +/*! + \internal +*/ +QCLImage3D QCLContextGL::createTexture3D + (QMacCompatGLenum type, QMacCompatGLuint texture, + QMacCompatGLint mipmapLevel, QCL::Access access) +{ + return createTexture3D(GLenum(type), GLuint(texture), + GLint(mipmapLevel), access); +} + +/*! + \internal +*/ +QCLImage3D QCLContextGL::createTexture3D + (QMacCompatGLuint texture, QCL::Access access) +{ + return createTexture3D(GLenum(GL_TEXTURE_3D), GLuint(texture), + GLint(0), access); +} + +/*! + \internal +*/ +QCLImage2D QCLContextGL::createRenderbuffer + (QMacCompatGLuint renderbuffer, QCL::Access access) +{ + return createRenderbuffer(GLuint(renderbuffer), access); +} + +#endif + +/*! + Returns true if the OpenCL \a buffer object is also an OpenGL + buffer object; false otherwise. +*/ +bool QCLContextGL::isGLBuffer(const QCLBuffer &buffer) +{ +#ifndef QT_NO_CL_OPENGL + cl_gl_object_type objectType; + if (clGetGLObjectInfo + (buffer.memoryId(), &objectType, 0) != CL_SUCCESS) + return false; + return objectType == CL_GL_OBJECT_BUFFER; +#else + return false; +#endif +} + +/*! + Returns true if the 2D OpenCL \a image object is also an OpenGL + 2D texture object; false otherwise. + + \sa isRenderbuffer(), isTexture3D() +*/ +bool QCLContextGL::isTexture2D(const QCLImage2D &image) +{ +#ifndef QT_NO_CL_OPENGL + cl_gl_object_type objectType; + if (clGetGLObjectInfo + (image.memoryId(), &objectType, 0) != CL_SUCCESS) + return false; + return objectType == CL_GL_OBJECT_TEXTURE2D; +#else + return false; +#endif +} + +/*! + Returns true if the 3D OpenCL \a image object is also an OpenGL + 3D texture object; false otherwise. + + \sa isTexture2D() +*/ +bool QCLContextGL::isTexture3D(const QCLImage3D &image) +{ +#ifndef QT_NO_CL_OPENGL + cl_gl_object_type objectType; + if (clGetGLObjectInfo + (image.memoryId(), &objectType, 0) != CL_SUCCESS) + return false; + return objectType == CL_GL_OBJECT_TEXTURE3D; +#else + return false; +#endif +} + +/*! + Returns true if the 2D OpenCL \a image object is also an OpenGL + renderbuffer object; false otherwise. + + \sa isTexture2D() +*/ +bool QCLContextGL::isRenderbuffer(const QCLImage2D &image) +{ +#ifndef QT_NO_CL_OPENGL + cl_gl_object_type objectType; + if (clGetGLObjectInfo + (image.memoryId(), &objectType, 0) != CL_SUCCESS) + return false; + return objectType == CL_GL_OBJECT_RENDERBUFFER; +#else + return false; +#endif +} + +/*! + Acquires access to the OpenGL object behind the OpenCL memory + object \a mem. This function must be called before performing + an OpenCL operation on any OpenGL memory object. + + Returns an event object that can be used to wait for the + request to finish. The request is executed on the active + command queue for this context. + + \sa release() +*/ +QCLEvent QCLContextGL::acquire(const QCLMemoryObject &mem) +{ +#ifndef QT_NO_CL_OPENGL + cl_event event; + cl_mem id = mem.memoryId(); + cl_int error = clEnqueueAcquireGLObjects + (commandQueue().queueId(), 1, &id, 0, 0, &event); + reportError("QCLContextGL::acquire:", error); + if (error == CL_SUCCESS) + return QCLEvent(event); + else + return QCLEvent(); +#else + return QCLEvent(); +#endif +} + +/*! + \overload + + Acquires access to the OpenGL object behind the OpenCL memory + object \a mem. This function must be called before performing + an OpenCL operation on any OpenGL memory object. + + The request will not start until all of the events in \a after + have been signaled as finished. + + Returns an event object that can be used to wait for the + request to finish. The request is executed on the active + command queue for this context. + + \sa release() +*/ +QCLEvent QCLContextGL::acquire + (const QCLMemoryObject &mem, const QCLEventList &after) +{ +#ifndef QT_NO_CL_OPENGL + cl_event event; + cl_mem id = mem.memoryId(); + cl_int error = clEnqueueAcquireGLObjects + (commandQueue().queueId(), 1, &id, + after.size(), after.eventData(), &event); + reportError("QCLContextGL::acquire(after):", error); + if (error == CL_SUCCESS) + return QCLEvent(event); + else + return QCLEvent(); +#else + Q_UNUSED(after); + return QCLEvent(); +#endif +} + +/*! + Releases access to the OpenGL object behind the OpenCL memory + object \a mem. This function must be called after performing + an OpenCL operation on any OpenGL memory object, and before + performing OpenGL operations on the object. + + Returns an event object that can be used to wait for the + request to finish. The request is executed on the active + command queue for this context. + + \sa acquire() +*/ +QCLEvent QCLContextGL::release(const QCLMemoryObject &mem) +{ +#ifndef QT_NO_CL_OPENGL + cl_event event; + cl_mem id = mem.memoryId(); + cl_int error = clEnqueueReleaseGLObjects + (commandQueue().queueId(), 1, &id, 0, 0, &event); + reportError("QCLContextGL::release:", error); + if (error == CL_SUCCESS) + return QCLEvent(event); + else + return QCLEvent(); +#else + return QCLEvent(); +#endif +} + +/*! + \overload + + Releases access to the OpenGL object behind the OpenCL memory + object \a mem. This function must be called after performing + an OpenCL operation on any OpenGL memory object, and before + performing OpenGL operations on the object. + + The request will not start until all of the events in \a after + have been signaled as finished. + + Returns an event object that can be used to wait for the + request to finish. The request is executed on the active + command queue for this context. + + \sa acquire() +*/ +QCLEvent QCLContextGL::release + (const QCLMemoryObject &mem, const QCLEventList &after) +{ +#ifndef QT_NO_CL_OPENGL + cl_event event; + cl_mem id = mem.memoryId(); + cl_int error = clEnqueueReleaseGLObjects + (commandQueue().queueId(), 1, &id, + after.size(), after.eventData(), &event); + reportError("QCLContextGL::release(after):", error); + if (error == CL_SUCCESS) + return QCLEvent(event); + else + return QCLEvent(); +#else + Q_UNUSED(after); + return QCLEvent(); +#endif +} + +QT_END_NAMESPACE diff --git a/src/openclgl/qclcontextgl.h b/src/openclgl/qclcontextgl.h new file mode 100644 index 0000000..0d5bcea --- /dev/null +++ b/src/openclgl/qclcontextgl.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenCL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCLCONTEXTGL_H +#define QCLCONTEXTGL_H + +#include "qclcontext.h" +#include <QtOpenGL/qgl.h> +#if QT_VERSION >= 0x040700 +#include <QtOpenGL/qglbuffer.h> +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(CL) + +class QCLContextGLPrivate; + +// Note: this class probably should be in the QtOpenGL library. +class Q_CLGL_EXPORT QCLContextGL : public QCLContext +{ +public: + QCLContextGL(); + ~QCLContextGL(); + + bool create(); + + bool supportsObjectSharing() const; + + QCLBuffer createGLBuffer(GLuint bufobj, QCL::Access access); +#if QT_VERSION >= 0x040700 || defined(Q_QDOC) + QCLBuffer createGLBuffer(QGLBuffer *bufobj, QCL::Access access); +#endif + + QCLImage2D createTexture2D + (GLenum type, GLuint texture, GLint mipmapLevel, QCL::Access access); + QCLImage2D createTexture2D(GLuint texture, QCL::Access access); + + QCLImage3D createTexture3D + (GLenum type, GLuint texture, GLint mipmapLevel, QCL::Access access); + QCLImage3D createTexture3D(GLuint texture, QCL::Access access); + + QCLImage2D createRenderbuffer(GLuint renderbuffer, QCL::Access access); + +#ifdef Q_MAC_COMPAT_GL_FUNCTIONS + QCLBuffer createGLBuffer(QMacCompatGLuint bufobj, QCL::Access access); + + QCLImage2D createTexture2D + (QMacCompatGLenum type, QMacCompatGLuint texture, + QMacCompatGLint mipmapLevel, QCL::Access access); + QCLImage2D createTexture2D(QMacCompatGLuint texture, QCL::Access access); + + QCLImage3D createTexture3D + (QMacCompatGLenum type, QMacCompatGLuint texture, + QMacCompatGLint mipmapLevel, QCL::Access access); + QCLImage3D createTexture3D(QMacCompatGLuint texture, QCL::Access access); + + QCLImage2D createRenderbuffer + (QMacCompatGLuint renderbuffer, QCL::Access access); +#endif + + static bool isGLBuffer(const QCLBuffer &buffer); + static bool isTexture2D(const QCLImage2D &image); + static bool isTexture3D(const QCLImage3D &image); + static bool isRenderbuffer(const QCLImage2D &image); + + QCLEvent acquire(const QCLMemoryObject &mem); + QCLEvent acquire + (const QCLMemoryObject &mem, const QCLEventList &after); + + QCLEvent release(const QCLMemoryObject &mem); + QCLEvent release + (const QCLMemoryObject &mem, const QCLEventList &after); + +private: + QScopedPointer<QCLContextGLPrivate> d_ptr; + + Q_DISABLE_COPY(QCLContextGL) + Q_DECLARE_PRIVATE(QCLContextGL) + + void reportError(const char *name, cl_int error); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/openclgl/qcltexture2d.cpp b/src/openclgl/qcltexture2d.cpp new file mode 100644 index 0000000..32d4da9 --- /dev/null +++ b/src/openclgl/qcltexture2d.cpp @@ -0,0 +1,337 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenCL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcltexture2d.h" +#include "qclcontextgl.h" +#include "qcl_glproxy_p.h" +#if QT_VERSION >= 0x040700 && !defined(QT_OPENGL_ES) +#include <QtOpenGL/qglbuffer.h> +#define USE_PIXEL_UNPACK_BUFFERS 1 +#endif + +QT_BEGIN_NAMESPACE + +/*! + \class QCLTexture2D + \brief The QCLTexture2D class represents a 2D OpenCL texture object. + \since 4.7 + \ingroup opencl + + Normally applications render into OpenGL textures by calling + QCLContextGL::createTexture2D() to wrap an existing texture identifier + with a QCLImage2D object. However, some systems do not support + the OpenCL/OpenGL sharing mechanisms that are needed to make that work. + + QCLTexture2D abstracts the creation and management of \c{GL_RGBA} + textures so that applications can render into them with OpenCL + kernels without needing to implement special handling for + OpenCL implementations that lack sharing. +*/ + +class QCLTexture2DPrivate : public QObject +{ + Q_OBJECT +public: + QCLTexture2DPrivate() + : context(0) + , clContext(0) + , textureId(0) + , directRender(false) +#ifdef USE_PIXEL_UNPACK_BUFFERS + , pixelBuffer(0) +#endif + { + } + ~QCLTexture2DPrivate() + { +#ifdef USE_PIXEL_UNPACK_BUFFERS + delete pixelBuffer; +#endif + } + + const QGLContext *context; + QCLContextGL *clContext; + GLuint textureId; + QSize size; + bool directRender; +#ifdef USE_PIXEL_UNPACK_BUFFERS + QGLBuffer *pixelBuffer; +#endif + + void setContextAndId(const QGLContext *ctx, GLuint id); + +private slots: + void aboutToDestroyContext(const QGLContext *ctx); +}; + +void QCLTexture2DPrivate::aboutToDestroyContext(const QGLContext *ctx) +{ + if (context == ctx) { + context = 0; + textureId = 0; + } +} + +void QCLTexture2DPrivate::setContextAndId(const QGLContext *ctx, GLuint id) +{ + context = ctx; + textureId = id; + connect(QGLSignalProxy::instance(), + SIGNAL(aboutToDestroyContext(const QGLContext *)), + this, + SLOT(aboutToDestroyContext(const QGLContext *))); +} + +/*! + Constructs an uninitialized OpenCL texture object. +*/ +QCLTexture2D::QCLTexture2D() + : QCLImage2D(), d_ptr(new QCLTexture2DPrivate()) +{ +} + +/*! + Destroys this OpenCL texture object. +*/ +QCLTexture2D::~QCLTexture2D() +{ + destroy(); +} + +/*! + Constructs an OpenCL texture of \a size in \a context. + Returns true if the texture was created; false otherwise. + + \sa destroy(), textureId() +*/ +bool QCLTexture2D::create(QCLContextGL *context, const QSize &size) +{ + Q_D(QCLTexture2D); + Q_ASSERT(context && size.width() > 0 && size.height() > 0); + Q_ASSERT(memoryId() == 0); // Must not be created already. + d->clContext = context; + + // Create the texture in the GL context. + GLuint textureId; + glGenTextures(1, &textureId); + glBindTexture(GL_TEXTURE_2D, textureId); +#ifdef GL_CLAMP_TO_EDGE + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +#else + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); +#endif + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, 0); + glBindTexture(GL_TEXTURE_2D, 0); + + // If the context supports object sharing, then this is really easy. + if (context->supportsObjectSharing()) { + QCLImage2D image = context->createTexture2D + (GL_TEXTURE_2D, textureId, 0, QCL::WriteOnly); + if (image.isNull()) { + glDeleteTextures(1, &textureId); + return false; + } + d->setContextAndId(QGLContext::currentContext(), textureId); + setId(image.context(), image.memoryId()); + d->size = size; + d->directRender = true; + return true; + } + +#ifdef USE_PIXEL_UNPACK_BUFFERS + // Create a pixel unpack buffer for downloading image data + // out of OpenCL and uploading it into OpenGL. + d->pixelBuffer = new QGLBuffer(QGLBuffer::PixelUnpackBuffer); + d->pixelBuffer->setUsagePattern(QGLBuffer::DynamicDraw); + if (d->pixelBuffer->create()) { + d->pixelBuffer->bind(); + d->pixelBuffer->allocate(size.width() * size.height() * 4); + d->pixelBuffer->release(); + } else { + delete d->pixelBuffer; + d->pixelBuffer = 0; + } +#endif + + // Create a 2D image in the OpenCL device for rendering with OpenCL. + QCLImage2D image = context->createImage2DDevice + (QCLImageFormat(QCLImageFormat::Order_RGBA, + QCLImageFormat::Type_Normalized_UInt8), + size, QCL::WriteOnly); + if (image.isNull()) { + glDeleteTextures(1, &textureId); +#ifdef USE_PIXEL_UNPACK_BUFFERS + delete d->pixelBuffer; + d->pixelBuffer = 0; +#endif + return false; + } + d->setContextAndId(QGLContext::currentContext(), textureId); + setId(image.context(), image.memoryId()); + d->size = size; + d->directRender = false; + return true; +} + +/*! + \fn bool QCLTexture2D::create(QCLContextGL *context, int width, int height) + \overload + + Constructs an OpenCL texture of size (\a width, \a height) + in \a context. Returns true if the texture was created; false otherwise. + + \sa destroy() +*/ + +/*! + Destroys this OpenCL texture object. +*/ +void QCLTexture2D::destroy() +{ + Q_D(QCLTexture2D); + setId(0, 0); + GLuint textureId = d->textureId; + if (textureId) { + QGLContext *oldContext; + QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext()); + if (currentContext != d->context && !QGLContext::areSharing(d->context, currentContext)) { + oldContext = currentContext; + const_cast<QGLContext *>(d->context)->makeCurrent(); + } else { + oldContext = 0; + } + glDeleteTextures(1, &textureId); + if (oldContext) + oldContext->makeCurrent(); + } +#ifdef USE_PIXEL_UNPACK_BUFFERS + delete d->pixelBuffer; + d->pixelBuffer = 0; +#endif + d->context = 0; + d->textureId = 0; + d->size = QSize(); + d->directRender = false; +} + +/*! + Acquires access to this texture so that OpenCL kernels + can render into it. OpenGL cannot use the texture until + release() is called. + + \sa release() +*/ +void QCLTexture2D::acquire() +{ + Q_D(QCLTexture2D); + if (d->directRender) + d->clContext->acquire(*this).waitForFinished(); +} + +/*! + Releases access to this texture so that OpenGL can use it again. + The textureId() will also be bound to the current OpenGL context. + + \sa acquire() +*/ +void QCLTexture2D::release() +{ + Q_D(QCLTexture2D); + if (!d->textureId) + return; + + // If we are doing direct rendering, then just release the OpenCL object. + if (d->directRender) { + d->clContext->release(*this).waitForFinished(); + glBindTexture(GL_TEXTURE_2D, d->textureId); + return; + } + + // Wait for the current OpenCL commands to finish. + context()->marker().waitForFinished(); + + // Upload the contents of the OpenCL buffer into the texture. + void *ptr; +#ifdef USE_PIXEL_UNPACK_BUFFERS + if (d->pixelBuffer) { + d->pixelBuffer->bind(); + ptr = d->pixelBuffer->map(QGLBuffer::ReadWrite); + if (ptr) { + read(ptr, QRect(QPoint(0, 0), d->size), d->size.width() * 4); + d->pixelBuffer->unmap(); + glBindTexture(GL_TEXTURE_2D, d->textureId); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, + d->size.width(), d->size.height(), + GL_RGBA, GL_UNSIGNED_BYTE, 0); + d->pixelBuffer->release(); + return; + } + // Pixel buffer cannot be mapped, so it is of no use to us. + d->pixelBuffer->release(); + delete d->pixelBuffer; + d->pixelBuffer = 0; + } +#endif + ptr = map(QRect(QPoint(0, 0), d->size), QCL::ReadOnly); + glBindTexture(GL_TEXTURE_2D, d->textureId); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, + d->size.width(), d->size.height(), + GL_RGBA, GL_UNSIGNED_BYTE, ptr); + unmap(ptr); +} + +/*! + Returns the OpenGL texture identifier for this OpenCL texture object. +*/ +GLuint QCLTexture2D::textureId() const +{ + Q_D(const QCLTexture2D); + return d->textureId; +} + +QT_END_NAMESPACE + +#include "qcltexture2d.moc" diff --git a/src/openclgl/qcltexture2d.h b/src/openclgl/qcltexture2d.h new file mode 100644 index 0000000..5d4f930 --- /dev/null +++ b/src/openclgl/qcltexture2d.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenCL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCLTEXTURE2D_H +#define QCLTEXTURE2D_H + +#include "qclimage.h" +#include <QtCore/qscopedpointer.h> +#include <QtOpenGL/qgl.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(CL) + +class QCLContextGL; +class QCLTexture2DPrivate; + +// Note: this class probably should be in the QtOpenGL library. +class Q_CLGL_EXPORT QCLTexture2D : public QCLImage2D +{ +public: + QCLTexture2D(); + ~QCLTexture2D(); + + bool create(QCLContextGL *context, const QSize &size); + bool create(QCLContextGL *context, int width, int height); + void destroy(); + + void acquire(); + void release(); + + GLuint textureId() const; + +private: + QScopedPointer<QCLTexture2DPrivate> d_ptr; + + Q_DISABLE_COPY(QCLTexture2D) + Q_DECLARE_PRIVATE(QCLTexture2D) +}; + +inline bool QCLTexture2D::create(QCLContextGL *context, int width, int height) +{ + return create(context, QSize(width, height)); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif |