尝试写第二个QOpenGLWidget程序 (未完成)

      按照QGLWidegt的教程很有问题,因为两个完全不同了。

      幸好搜到了官方的blog,http://blog.qt.io/blog/2014/09/10/qt-weekly-19-qopenglwidget/,文章前面就是说QOpenGLWidegt比QGLWidegt好,然后 (嵌入式就是es的,和desktop差不多的)

Benefits for Desktop

Of course, it is not just for OpenGL ES. On desktop platforms, OpenGL 3.x and 4.x, including core profiles, are fully supported. Unlike QGLWidget, which forced the usage of legacy and often incomplete utility classes like QGLFormat and QGLContext, QOpenGLWidget uses the modern equivalents from the QtGui module: QSurfaceFormat, QOpenGLContext and the other, modern QOpenGL classes.

The basic API is same as in QGLWidget. For example, a simple subclass could look like the following:

class Widget : public QOpenGLWidget, protected QOpenGLFunctions
{
public:
    Widget(QWidget *parent = 0);
    void initializeGL();
    void resizeGL(int w, int h);
    void paintGL();

private:
    QMatrix4x4 m_projection;
};

Widget::Widget(QWidget *parent) : QOpenGLWidget(parent)
{
    QSurfaceFormat format;
    format.setDepthBufferSize(24);
    setFormat(format);
}

void Widget::initializeGL()
{
    initializeOpenGLFunctions();
}

void Widget::resizeGL(int w, int h)
{
    m_projection.setToIdentity();
    m_projection.perspective(60.0f, w / float(h), 0.01f, 1000.0f);
}

void Widget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    ...
}
This should look quite familiar to those who have used QGLWidget before.

在5.6的blog文章中有es的文章

http://blog.qt.io/blog/2015/09/09/cross-platform-opengl-es-3-apps-with-qt-5-6/

Cross-platform OpenGL ES 3 apps with Qt 5.6

Published Wednesday September 9th, 2015
7 Comments on Cross-platform OpenGL ES 3 apps with Qt 5.6 
Posted in Embedded, Graphics, Mobile, OpenGL

Now that the alpha release for Qt 5.6 is here, it is time to take a look at some of the new features. With the increasing availability of GPUs and drivers capable of OpenGL ES 3.0 and 3.1 in the mobile and embedded world, targeting the new features these APIs provide has become more appealing to applications. While nothing stops the developer from using these APIs directly (that is, #include <GLES3/gl3.h>, call the functions directly, and be done with it), the cross-platform development story used to be less than ideal, leading to compile and run-time checks scattered across the application. Come Qt 5.6, this will finally change.

Support for creating versioned OpenGL (ES) contexts has been available in Qt 5 for some time. Code snippets like the following should therefore present no surprises:

1
2
3
4
5
6
7
8
9
int main( int argc, char **argv) {
     QSurfaceFormat fmt;
     fmt.setVersion(3, 1);
     fmt.setDepthBufferSize(24);
     QSurfaceFormat::setDefaultFormat(fmt);
 
     QGuiApplication app(argc, argv);
     ...
}

It is worth pointing out that due to the backwards compatible nature of OpenGL ES 3 this may seem unnecessary with many drivers because requesting the default 2.0 will anyway result in a context for the highest supported OpenGL ES version. However, this behavior is not guaranteed by any specification (see for exampleEGL_KHR_create_context) and therefore it is best to set the desired version explicitly.

The problem

So far so good. Assuming we are running on an OpenGL ES system, we now have a context and everything ready to utilize all the goodness the API offers. Except that we have no way to easily invoke any of the 3.0 or 3.1 specific functions, unless the corresponding gl3.h or gl31.h header is included and Qt is either a -opengl es2 build or the application explicitly pulled in -lGLESv2 in its .pro file. In which case we can wave goodbye to our sources’ cross-platform, cross-OpenGL-OpenGL ES nature.

For OpenGL ES 2.0 the problem has been solved for a long time now byQOpenGLFunctions. It exposes the entire OpenGL ES 2.0 API and guarantees that the functions are resolved correctly everywhere where an OpenGL context compatible with either OpenGL ES 2.0 or OpenGL 2.0 plus the FBO extension is available.

Before moving on to introducing the counterpart for OpenGL ES 3.0 and 3.1, it is important to understand why the versioned OpenGL function wrappers (for example, QOpenGLFunctions_3_2_Core) are not a solution to our problem here. The versioned wrappers are great when targeting a given version and profile of the OpenGL API. However, they lock in the application to systems that support that exact OpenGL version and profile, or a version and profile compatible with it. Building and running the same source code on an OpenGL ES system is out of question, even when the code only uses calls that are available in OpenGL ES as well. So it turns out that strict enforcement of the compatibility rules for the entire OpenGL API is not always practical.

Say hello to QOpenGLExtraFunctions

To overcome all this, Qt 5.6 introduces QOpenGLExtraFunctions. Why “extra” functions? Because adding all this to QOpenGLFunctions would be wrong in the sense that everything in QOpenGLFunctions is guaranteed to be available (assuming the system meets Qt’s minimum OpenGL requirements), while these additional functions (the ES 3.0/3.1 API) may be dysfunctional in some cases, for example when running with a real OpenGL (ES) 2.0 context.

The usage is identical to QOpenGLFunctions: either query a context-specific instance from QOpenGLContext via QOpenGLContext::extraFunctions() or subclass and use protected inheritance. How the functions get resolved internally (direct call, dynamic resolving via dlsym/GetProcAddress, or resolving via the extension mechanism, i.e. eglGetProcAddress and friends) is completely transparent to the applications. As long as the context is OpenGL ES 3 or a version of OpenGL with the function in question available as an extension, it will all just work.

As an example let’s try to write an application that uses instanced drawing via glDrawArraysInstanced. We want it to run on mobile devices with OpenGL ES 3.0 and any desktop system where OpenGL 3.x (compatibility profile) is available. Needless to say, we want as little branching and variation in the code as possible.

For the impatient, the example is part of Qt and can be browsed online here.

Now let’s take a look at the most important pieces of code that allow the cross-OpenGL-OpenGL ES behavior.

Context versioning

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main( int argc, char *argv[])
{
     QSurfaceFormat fmt;
     fmt.setDepthBufferSize(24);
     if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) {
         fmt.setVersion(3, 3);
         fmt.setProfile(QSurfaceFormat::CompatibilityProfile);
     } else {
         fmt.setVersion(3, 0);
     }
     QSurfaceFormat::setDefaultFormat(fmt);
     QGuiApplication app(argc, argv);
     ...
}

This looks familiar. Except that now, in addition to opting for version 3.0 with OpenGL ES, we request 3.3 compatibility when running with OpenGL. This is important because we know that instanced drawing is available there too. Therefore glDrawArraysInstanced will be available no matter what.

The fact that we are doing runtime checks instead of ifdefs is due to the dynamic OpenGL implementation loading on some platforms, for example Windows, introduced in Qt 5.4. There it is not necessarily known until runtime if the implementation provides OpenGL (opengl32.dll) or OpenGL ES (ANGLE).

Note that it may still be a good idea to check the actual version after the QOpenGLContext (or QOpenGLWidget, QQuickView, etc.) is initialized, just to be safe.QOpenGLContext::format(), once the context is sucessfully create()’ed, always contains the actual, not the requested, version and other information.

Astute readers may now point out that it should also be possible to request an OpenGL ES context unconditionally in case GLX_EXT_create_context_es2_profile or similar is supported. This would mean that instead of branching based onopenGLModuleType(), one could simply set the format’s renderableType toQSurfaceFormat::OpenGLES. The disadvantage is obvious: that approach just won’t work on many systems. Hence we stick to compatibility profile contexts when running with OpenGL.

Shader version directive

1
2
3
4
if (QOpenGLContext::currentContext()->isOpenGLES())
     versionedSrc.append(QByteArrayLiteral( "#version 300 es\n" ));
else
     versionedSrc.append(QByteArrayLiteral( "#version 330\n" ));

What’s this? Our shader code is written in the modern GLSL syntax and is simple and compatible enough between GLSL and GLSL ES. However, there is a one line difference we have to take care of: the version directive. This is easy enough to fix up.

Note that with OpenGL implementations supporting GL_ARB_ES3_compatbility this is not needed as these should be able to handle 300 es shaders too. However, in order to target the widest possible range of systems, we avoid relying on that extension for now.

Calling ES 3 functions

1
2
3
QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
...
f->glDrawArraysInstanced(GL_TRIANGLES, 0, m_logo.vertexCount(), 32 * 36);

And here’s why this is great: the actual API call is the same between OpenGL and OpenGL ES, desktop and mobile or embedded platforms. No checks, conditions, or different wrapper objects are needed.

Below a screenshot of the application running on a Linux PC and on an Android tablet with no changes to the source code. (What’s better than a single Qt logo? A Qt logo composed of 1152 Qt logos of course!)

The hellogles3 example running on Linux. Make sure to check it out live in all its animated glory as the photos do no justice to it.

尝试写第二个QOpenGLWidget程序 (未完成)_第1张图片

The exact same app running on Android

Summary

To summarize which API wrapper to use and when, let’s go through the possible options:

  • QOpenGLFunctions – The number one choice, unless OpenGL 3/4.x features are desired and the world outside the traditional desktop platforms is not interesting to the application. Cross-platform applications intending to run on the widest possible range of systems are encouraged to to stick to this one, unless they are prepared to guard the usage of OpenGL features not in this class with appropriate runtime checks. QOpenGLFunctions is also what Qt Quick and various other parts of Qt use internally.
  • QOpenGLExtraFunctions – Use it in addition to QOpenGLFunctions whenever OpenGL ES 3.0 and 3.1 features are needed.
  • Versioned wrappers (QOpenGLFunctions_N_M_profile) – When an OpenGL 3/4.x core or compatibility profile is needed and targeting OpenGL ES based systems is not desired at all.

Bonus problem: the headers

Before going back to coding, an additional issue needs explaining: what about theGL_* constants and typedefs? Where do the OpenGL ES 3.x specific ones come from if the application does not explicitly include GLES3/gl3.h or gl31.h?

As a a general rule Qt applications do not include OpenGL headers themselves.qopengl.h, which is included by the QOpenGL class headers, takes care of this.

  • In -opengl es2 builds of Qt, which is typical on mobile and embedded systems,qopengl.h includes the header for the highest possible ES version that was found when running configure for Qt. So if the SDK (sysroot) came withGLES3/gl31.h, then applications will automatically have everything from gl31.havailable.
  • In -opengl desktop and -opengl dynamic builds of Qt the ES 3.0 and 3.1 constants are available because they are either part of the system’s gl.h or come from Qt’s own internal copy of glext.h, where the latter conveniently gives us all constants up to OpenGL 4.5 and is included as well fromqopengl.h.

So in many cases it will all just magically work. There is a problematic scenario, in particular on mobile, though: if only gl2.h was available when building Qt, then applications will not get gl3.h or gl31.h included automatically even if the SDK against which applications are built has those. This can be a problem on Android for example, when Qt is built against an older NDK that does not come with ES 3 headers. For the time being this can be worked around in the applications by explicitly including gl3.h or gl31.h guarded by an ifdef for Q_OS_ANDROID.

That is all for now. For those wishing to hear more about the exciting news in Qt’s graphics world, Qt World Summit is the place to be. See you there in October!

Do you like this? Share it

Posted in Embedded, Graphics, Mobile, OpenGL

7 comments

尝试写第二个QOpenGLWidget程序 (未完成)_第2张图片 Giuseppe

Note that there are also versioned functions for ES2. We should definitely add the ones for ES3 / 3.1…

尝试写第二个QOpenGLWidget程序 (未完成)_第3张图片 Laszlo Agocs

Correct. However the usefulness of the ES2 wrapper is pretty limited already: it only works with true OpenGL ES contexts, relies on directly invoking the GL functions, and is as a consequence only available in -opengl es2 builds of Qt. In this case one could just directly call the functions as libGLESv2 is guaranteed to be available. The concept of targeting a given version/profile of OpenGL does not really play nice anymore when OpenGL ES gets thrown into the mix, with applications potentially wanting to be functional everywhere with the least amount of variation in the source code.

尝试写第二个QOpenGLWidget程序 (未完成)_第4张图片 jiangcaiyang

With OpenGL ES 3.x noted as QOpenGLExtraFunctions, what if in the future OpenGL 5.0 ( ES ) takes the ownership of cross platform industry graphics APIs? is “extra” enough? What if we take QOpenGLFunctions as a macro and determined by user’s developing environment?

尝试写第二个QOpenGLWidget程序 (未完成)_第5张图片 jiangcaiyang

Also what about future devices such as Lumias support Direct3D 11/12 and we can use ANGLE to translate to OpenGL ES 3, these features can be supported by the ongoing QOpenGLExtraFunctions?

尝试写第二个QOpenGLWidget程序 (未完成)_第6张图片 Laszlo Agocs

Yes, once ANGLE provides a full ES 3.0 implementation, the corresponding set of functions will become functional also when running on ANGLE. For now it is limited to ES 2.0, though.

尝试写第二个QOpenGLWidget程序 (未完成)_第7张图片 Scorp1us

Is there anything possible or in the pipeline for OpenCL?

I’m not a GL expert, so I am not sure how I could convert OpenCL code to ES.

尝试写第二个QOpenGLWidget程序 (未完成)_第8张图片 HGH

Why no support for ES 3.2 now?
It was released before the alpha?
Will it take forever to add it in the future?




你可能感兴趣的:(尝试写第二个QOpenGLWidget程序 (未完成))