1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
|
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the documentation 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 either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** 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.0, 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\example qws/ahigl
\title OpenGL for Embedded Systems Example
\section1 Introduction
This example demonstrates how you can use OpenGL for Embedded
Systems (ES) in your own screen driver and \l{add your graphics
driver to Qt for Embedded Linux}. In \l{Qt for Embedded Linux},
painting is done in software, normally performed in two steps:
First, each client renders its windows onto its window surface in
memory using a paint engine. Then the server uses the screen
driver to compose the window surface images and copy the
composition to the screen. (See the \l{Qt for Embedded Linux
Architecture} documentation for details.)
This example is not for the novice. It assumes the reader is
familiar with both OpenGL and the screen driver framework
demonstrated in the \l {Accelerated Graphics Driver Example}.
An OpenGL screen driver for Qt for Embedded Linux can use OpenGL ES
in three ways. First, the \l{QWSServer}{Qt for Embedded Linux server}
can use the driver to compose multiple window images and then show the
composition on the screen. Second, clients can use the driver to
accelerate OpenGL painting operations using the QOpenGLPaintEngine
class. Finally, clients can use the driver to do OpenGL operations
with instances of the QGLWidget class. This example implements all
three cases.
The example uses an implementation of OpenGL ES from
\l {http://ati.amd.com}{ATI} for the
\l {http://ati.amd.com/products/imageon238x/}{Imageon 2380}. The
OpenGL include files gl.h and egl.h must be installed to compile
the example, and the OpenGL and EGL libraries must be installed
for linking. If your target device is different, you must install
the include files and libraries for that device, and you also
might need to modify the example source code, if any API signatures
in your EGL library differ from the ones used here.
After compiling and linking the example source, install the
screen driver plugin with the command \c {make install}. To
start an application that uses the plugin, you can either set the
environment variable \l QWS_DISPLAY and then start the
application, or just start the application with the \c -display
switch, as follows:
\snippet doc/src/snippets/code/doc_src_examples_ahigl.qdoc 0
The example driver also implements an animated transition effect
for use when showing new windows or reshowing windows that have
been minimized. To enable this transition effect, run the
application with \c {-display ahigl:effects}.
\section1 The Class Definitions
The example comprises three main classes plus some helper classes.
The three main classes are the plugin (QAhiGLScreenPlugin), which
is defined in qscreenahiglplugin.cpp, the screen driver
(QAhiGLScreen), which is defined in qscreenahigl_qws.h, and the
window surface (QAhiGLWindowSurface), which is defined in
qwindowsurface_ahigl_p.h. The "Ahi" prefix in these class names
stands for \e {ATI Handheld Interface}. The example was written
for the ATI Imageon 2380, but it can also be used as a template
for other ATI handheld devices.
\section2 The Plugin Class Definition
The screen driver plugin is class QAhiGLScreenPlugin.
\snippet examples/qws/ahigl/qscreenahiglplugin.cpp 0
QAhiGLScreenPlugin is derived from class QScreenDriverPlugin,
which in turn is derived from QObject.
\section2 The Screen Driver Class Definitions
The screen driver classes are the public class QAhiGLScreen and
its private implementation class QAhiGLScreenPrivate. QAhiGLScreen
is derived from QGLScreen, which is derived from QScreen. If your
screen driver will only do window compositions and display them,
then you can derive your screen driver class directly from
QScreen. But if your screen driver will do accelerated graphics
rendering operations with the QOpenGLPaintEngine, or if it will
handle instances of class QGLWidget, then you must derive your
screen driver class from QGLScreen.
\snippet examples/qws/ahigl/qscreenahigl_qws.h 0
All functions in the public API of class QAhiGLScreen are virtual
functions declared in its base classes. hasOpenGL() is declared in
QGLScreen. It simply returns true indicating our example screen
driver does support OpenGL operations. The other functions in the
public API are declared in QScreen. They are called by the
\l{QWSServer}{Qt for Embedded Linux server} at the appropriate times.
Note that class QScreen is a documented class but class QGLScreen
is not. This is because the design of class QGLScreen is not yet
final.
The only data member in class QAhiGLScreen is a standard d_ptr,
which points to an instance of the driver's private implementation
class QAhiGLScreenPrivate. The driver's internal state is stored
in the private class. Using the so-called d-pointer pattern allows
you to make changes to the driver's internal design without
breaking binary compatibility.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 0
Class QAhiGLScreenPrivate is derived from QObject so that it can
use the Qt signal/slot mechanism. QAhiGLScreen is not a QObject,
so it can't use the signal/slot mechanism. Signals meant for our
screen driver are received by slots in the private implementation
class, in this case, windowEvent() and redrawScreen().
\section2 The Window Surface Class Definitions
The window surface classes are QAhiGLWindowSurface and its private
implementation class QAhiGLWindowSurfacePrivate. We create class
QAhiGLWindowSurface so the screen driver can use the OpenGL paint
engine and the OpenGL widget, classes QOpenGLPaintEngine and
QGLWidget. QAhiGLWindowSurface is derived from the more general
OpenGL window surface class, QWSGLWindowSurface, which is derived
from QWSWindowSurface.
\snippet examples/qws/ahigl/qwindowsurface_ahigl_p.h 0
In addition to implementing the standard functionality required by
any new subclass of QWSWindowSurface, QAhiGLWindowSurface also
contains the textureId() function used by QAhiGLScreen.
The same d-pointer pattern is used in this window surface class.
The private implementation class is QAhiGLWindowSurfacePrivate. It
allows making changes to the state variables of the window surface
without breaking binary compatibility.
\snippet examples/qws/ahigl/qwindowsurface_ahigl.cpp 0
In this case, our private implementation class has no member
functions except for its constructor. It contains only public data
members which hold state information for the window surface.
\section2 The Helper Classes
The example screen driver maintains a static \l {QMap} {map} of
all the \l {QWSWindow} {windows} it is showing on the screen.
Each window is mapped to an instance of struct WindowInfo.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 2
As each new window is created, an instance of struct WindowInfo is
allocated and inserted into the window map. WindowInfo uses a
GLuint to identify the OpenGL texture it creates for the window.
Note that the example driver, in addition to drawing windows using
OpenGL, also supports drawing windows in the normal way without
OpenGL, but it uses an OpenGL texture for the rendering operations
in either case. Top-level windows that are drawn without OpenGL
are first rendered in the normal way into a shared memory segment,
which is then converted to a OpenGL texture and drawn to the
screen.
To animate the window transition effect, WindowInfo uses an
instance of the helper class ShowAnimation. The animation is
created by the windowEvent() slot in QAhiGLScreenPrivate, whenever
a \l {QWSServer::WindowEvent} {Show} window event is emitted by
the \l {QWSServer} {window server}. The server emits this signal
when a window is shown the first time and again later, when the
window is reshown after having been minimized.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 1
Class ShowAnimation is derived from the QTimeLine class, which is
used for controlling animations. QTimeLine is a QObject, so
ShowAnimation can use the Qt signal/slot mechanism. We will see
how the timeline's \l {QTimeLine::valueChanged()} {valueChanged()}
and \l {QTimeLine::finished()} {finished()} signals are used to
control the animation and then destroy the instance of
ShowAnimation, when the animation ends. The ShowAnimation
constructor needs the pointer to the screen driver's private
implementation class so it can set up these signal/slot
connections.
\section1 The Class Implementations
\section2 The Plugin Class Implementation
QAhiGLScreenPlugin is a straightforward derivation of
QScreenDriverPlugin. It reimplements \l{QScreenDriverPlugin::}{keys()}
and \l{QScreenDriverPlugin::}{create()}. They are
called as needed by the \l{QWSServer}{Qt for Embedded Linux server.}
Recall that the server detects that the ahigl screen driver has
been requested, either by including "ahigl" in the value for the
environment variable QWS_DISPLAY, or by running your application
with a command line like the following.
\snippet doc/src/snippets/code/doc_src_examples_ahigl.qdoc 1
The server calls \l {QScreenDriverPlugin::} {keys()}, which
returns a \l {QStringList} containing the singleton "ahigl"
matching the requested screen driver and telling the server that
it can use our example screen driver. The server then calls \l
{QScreenDriverPlugin::} {create()}, which creates the instance of
QAhiGLScreen.
\snippet examples/qws/ahigl/qscreenahiglplugin.cpp 1
In the code snippet above, the macro Q_EXPORT_PLUGIN2 is used to export
the plugin class, QAhiGLScreen, for the qahiglscreen plugin.
Further information regarding plugins and how to create them
can be found at \l{How to Create Qt Plugins}.
\section2 The Screen Driver Class Implementations
The plugin creates the singleton instance of QAhiGLScreen. The
constructor is passed a \c displayId, which is used in the base
class QGLScreen to identify the server that the screen driver is
connected to. The constructor also creates its instance of
QAhiGLScreenPrivate, which instantiates a QTimer. The timeout()
signal of this timer is connected to the redrawScreen() slot so
the timer can be used to limit the frequency of actual drawing
operations in the hardware.
The public API of class QAhiGLScreen consists of implementations
of virtual functions declared in its base classes. The function
hasOpenGL() is declared in base class QGLScreen. The others are
declared in base class QScreen.
The \l {QScreen::}{connect()} function is the first one called by
the server after the screen driver is constructed. It initializes
the QScreen data members to hardcoded values that describe the ATI
screen. A better implementation would query the hardware for the
corresponding values in its current state and use those. It asks
whether the screen driver was started with the \c effects option
and sets the \c doEffects flag accordingly.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 7
The \l {QScreen::}{initDevice()} function is called by the server
after \l {QScreen::}{connect()}. It uses EGL library functions to
initialize the ATI hardware. Note that some data structures used
in this example are specific to the EGL implementation used, e.g.,
the DummyScreen structure.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 8
Note the signal/slot connection at the bottom of initDevice(). We
connect the server's QWSServer::windowEvent() signal to the
windowEvent() slot in the screen driver's private implementation
class. The windowEvent() slot handles three window events,
QWSServer::Create, QWSServer::Destroy, and QWSServer::Show.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 5
The function manages instances of the helper classes associated
with each window. When a QWSServer::Create event occurs, it means
a new top-level \l {QWSWindow} {window} has been created. In this
case, an instance of helper class WindowInfo is created and
inserted into the window map with the pointer to the new \l
{QWSWindow} {window} as its key. When a QWSServer::Destroy event
occurs, a window is being destroyed, and its mapping is removed
from the window map. These two events are straightforward. The
tricky bits happen when a QWSServer::Show event occurs. This case
occurs when a window is shown for the first time and when it is
reshown after having been minimized. If the window transition
effect has been enabled, a new instance of the helper class
ShowAnimation is created and stored in a QPointer in the window's
instance of WindowInfo. The constructor of ShowAnimation
automatically \l {QTimeLine::start()} {starts} the animation of
the transition effect.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 3
To ensure that a ShowAnimation is not deleted until its animation
ends, the \l {QTimeLine::finished()} {finished()} signal is
connected to the \l {QObject::deleteLater()} {deleteLater()} slot.
When the animation ends, the finished() signal is emitted and the
deleteLater() slot deletes the ShowAnimation. The key here is that
the pointer to the ShowAnimation is stored in a QPointer in the
WindowInfo class. This QPointer will also be notified when the
ShowAnimation is deleted, so the QPointer in WindowInfo can null
itself out, if and only if it is still pointing to the instance
of ShowAnimation being deleted.
The \l {QTimeLine::valueForTime()} {valueForTime()} function in
QTimeLine is reimplemented in ShowAnimation to return time values
that represent a curved path for the window transition effect.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 4
valueForTime() is called internally, when the time interval it
computed during the previous call has elapsed. If it computes a
next time value that is different from the one computed
previously, the \l {QTimeLine::valueChanged()} {valueChanged()}
signal is emitted. The ShowAnimation constructor shown above
connects this signal to the redrawScreen() slot in the screen
driver's private implementation class. This is how the animation
actually happens.
The screen driver's implementation of \l {QScreen::}
{exposeRegion()} is where the main work of the screen driver is
meant to be done, i.e., updating the screen. It is called by the
\l {QWSServer} {window system} to update a particular window's
region of the screen. But note that it doesn't actually update the
screen, i.e., it doesn't actually call redrawScreen() directly,
but starts the updateTimer, which causes redrawScreen() to be
called once for each updateTimer interval. This means that all
calls to exposeRegion() during an updateTimer interval are handled
by a single call to redrawScreen(). Thus updateTimer can be used
to limit the frequency of screen updates.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 13
The call to the private function invalidateTexture() destroys
the window's existing texture (image). This ensures that a new
texture will be created for the window, when redrawScreen() is
eventually called.
But there is a caveat to using updateTimer to limit the frequency
of screen updates. When the driver's animated transition effect
for new windows is enabled and a new window is being shown for the
first time or reshown after having been minimized, an instance of
ShowAnimation is created to run the animation. The valueChanged()
signal of this ShowAnimation is also connected to the
redrawScreen() slot, and QTimeLine, the base class of our
ShowAnimation, uses its own, internal timer to limit the speed of
the animation. This means that in the driver as currently written,
if the window transition effect is enabled (i.e. if the plugin is
started, with \c {-display ahigl:effects}), then redrawScreen()
can be called both when the update timer times out and when the
ShowAnimation timer times out, so the screen might get updated
more often than the frequency established by the update timer.
This may or may not be a bug, depending on your own hardware, if
you use this example as a template for your own OpenGL driver.
The screen driver's private function redrawScreen() constructs
the window compositions. It is called only by the function of the
same name in the screen driver's private implementation class.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 6
Recall that this redrawScreen() in the private implementation
class is a slot function connected to two signals, the \c
timeout() signal of the updateTimer in the private implementation
class, and the valueChanged() signal of the helper class
ShowAnimation. Thus, the screen is only ever updated when a
timeout of one of the two timers occurs. This is important for two
reasons. First, the screen is meant to be updated no more than
once per updateTimer interval. Second, however, if the animated
window transition effect is requested, the screen might be updated
more often than that, and this might be a bug if the hardware
can't handle more frequent updates.
The redrawScreen() in QAhiGLScreen begins by using standard
OpenGL to fill the screen with the background color.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 10
Next it iterates over the list of all \l {QWSWindow} {client
windows} obtained from the \l {QWSServer} {server}, extracting
from each window its instance of QWSWIndowSurface, then using that
window surface to create an OpenGL texture, and finally calling
the helper function drawWindow() to draw the texture on the
screen.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 11
Note the call to glBindTexture() immediately before the call to
drawWindow(). This call binds the identifer \c GL_TEXTURE_2D to
the texture we have just created. This makes our texture
accessible to functions in the OpenGL libraries. If you miss that
point, digging into the internals of drawWindow() won't make much
sense.
Finally, the cursor is added to the window composition, and in the
last statement, the whole thing is displayed on the screen.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 12
The call to \c drawWindow(win,progress), in addition to passing a
pointer to the window to be redrawn, also passes the \c progress
parameter obtained by calling \l {QTimeLine::currentValue()} on
the window's instance of ShowAnimation. Recall that the current
value of the timeline is updated internally by a timer local to
the timeline, and the redrawScreen() slot is called whenever the
current value changes. The progress value will only be used if
the animated transition effect has been enabled. These extra calls
of redrawScreen() may cause the screen to be updated more often
than the rate determined by updateTimer. This must be taken
into account, if you set your updateTimer to timeout at the
maximum screen update frequency your hardware can handle.
The drawWindow() function is not shown here and not explained
further, but the call to drawWindow() is the entry point to a
hierarchy of private helper functions that execute sequences of
OpenGL and EGL library calls. The reader is assumed to be familiar
enough with the OpenGL and EGL APIs to understand the code in
these helper functions on his own. Besides drawWindow(), the list
of these helper functions includes drawQuad(), drawQuadWavyFlag(),
the two overloadings of drawQuad_helper() (used by drawQuad() and
drawQuadWacyFlag()), and setRectCoords().
Note the two different ways the window's texture can be created in
redrawScreen(). If the window surface is an OpenGL window surface
(QAhiGLWindowSurface described below), the texture is obtained
from the window surface directly by calling its textureId()
function. But when the window surface is not an OpenGL one, the
static function createTexture() is called with the window
surface's \l {QImage} {image} to copy that image into an OpenGL
texture. This is done with the EGL functions glTexImage2D() and
glTexSubImage2D(). createTexture() is another function that
should be understandable for exsperienced OpenGL users, so it is
not shown or explained further here.
The two implementations of \l {QScreen::}{createSurface()} are for
instantiating new window surfaces. The overloading with the widget
parameter is called in the client.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 14
If the parameter is an \l {QGLWidget} {OpenGL widget}, or, when it
isn't an OpenGL widget but its size is no bigger than 256 x 256,
we instantiate our subclass QAhiGLWindowSurface. Otherwise, we
instantiate a QWSWindowSurface. The size contraint is a
limitation of the OpenGL ES libraries we are using for our ATI
device.
Note the test at the top of the function asking if our application
process is the \l {QApplication::GuiServer} {server}. We only
create instances of QAhiGLWindowSurface if our client is in the
server process. This is because of an implementation restriction
required by the OpenGL library used in the example. They only
support use of OpenGL in the server process. Hence a client can
use the QAhiGLWindowSurface if the client is in the server
process.
The other overloading of createSurface() is called by the
server to create a window surface that will hold a copy of a
client side window surface.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 15
This overloading accepts a QString parameter identifying the type
of window surface to instantiate. QAhiGLWindowSurface is
instantiated if the parameter is \c ahigl. Otherwise, a normal
QWSWindowSurface is instantiated. The client's window surface
communicates its image data to the server's window surface through
shared memory.
The implementation of \l {QScreen::}{setMode()}, is a stub in this
example. It would normally reset the frame buffer's resolution.
Its parameters are the \e width, \e height, and the bit \e depth
for the frame buffer's new resolution. If you implement setMode()
in your screen driver, remember that it must emit a signal to warn
other applications to redraw their frame buffers with the new
resolution. There is no significance to setMode() not being
implemented in this example. It simply wasn't implemented.
However, the stub had to be included because QScreen declares
setMode() to be pure virtual.
Before the application exits, the server will call \l {QScreen::}
{shutdownDevice()} to release the hardware resources. This is also
done using EGL library functions.
\snippet examples/qws/ahigl/qscreenahigl_qws.cpp 9
The server will also call \l {QScreen::}{disconnect()}, but this
function is only a stub in this example.
\section2 The window Surface Class Implementations
QAhiGLScreen creates instances of QAhiGLWindowSurface in its two
createSurface() functions, and there are two constructors for
QAhiGLWindowSurface that correspond to these two versions of
createSurface(). The constructor accepting a \l {QWidget} {widget}
parameter is called by the client side version of createSurface(),
and the constructor without the \l {QWidget} {widget} parameter is
called by the server side version. There will be a window surface
constructed on the server side for each one constructed on the
client side.
\snippet examples/qws/ahigl/qwindowsurface_ahigl.cpp 1
\codeline
\snippet examples/qws/ahigl/qwindowsurface_ahigl.cpp 2
The constructors create an instance of QAhiGLWindowSurfacePrivate,
the private implementation class, which contains all the state
variables for QAhiGLWindowSurface. The client side constructor
also creates an instance of QWSGLPaintDevice, the OpenGL paint
device, for return by \l {QWSWindowSurface::} {paintDevice()}.
This ensures that all \l {QPainter}s used on this surface will use
an OpenGL enabled QPaintEngine. It is a bit of jiggery pokery,
which is required because \l {QWSWindowSurface::} {paintDevice()}
is declared pure virtual. Normally, the client side constructor
will be called with an \l {QGLWidget}{OpenGL widget}, which has
its own \l {QWidget::} {paintEngine()} function that returns the
global static OpenGL paint engine, but because the constructor
also accepts a normal \l {QWidget}{widget}, it must be able to
find the OpenGL paint engine in that case as well, so since \l
{QWSWindowSurface::} {paintDevice()} must be implemented anyway,
the constructor creates an instance of QWSGLPaintDevice, which can
always return the global static pointer to QOpenGLPaintEngine.
The OpenGL library implementation used for this example only
supports one OpenGL context. This context is therefore shared
among the single instance of QAhiGLScreen and all instances of
QAhiGLWindowSurface. It is passed to both constructors.
This example uses the OpenGL frame buffer object extension, which
allows for accelerating OpenGL painting operations. Using this
OpenGL extension, painting operations are performed in a frame
buffer object, which QAhiGLScreen later uses to construct window
compositions on the screen. Allocation of the frame buffer object
is performed in \l {QWindowSurface::} {setGeometry()}. A safer way
to use this extension would be to first test to see if the
extension is supported by your OpenGL library, and use a different
approach if it is not.
\snippet examples/qws/ahigl/qwindowsurface_ahigl.cpp 3
Since there can be several instances of the QAhiGLWindowSurface, we need
to make sure that the correct framebuffer object is active before painting.
This is done by reimplementing \l QWindowSurface::beginPaint():
\snippet examples/qws/ahigl/qwindowsurface_ahigl.cpp 4
Finally we need to make sure that whenever a widget grows beyond the size
supported by this driver (256 x 256), the surface is deleted and a new
standard surface is created instead. This is handled by reimplementing
\l QWSWindowSurface::isValid():
\snippet examples/qws/ahigl/qwindowsurface_ahigl.cpp 5
*/
|