0
|
1 |
/****************************************************************************
|
|
2 |
**
|
|
3 |
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
4 |
** All rights reserved.
|
|
5 |
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
6 |
**
|
|
7 |
** This file is part of the documentation of the Qt Toolkit.
|
|
8 |
**
|
|
9 |
** $QT_BEGIN_LICENSE:LGPL$
|
|
10 |
** No Commercial Usage
|
|
11 |
** This file contains pre-release code and may not be distributed.
|
|
12 |
** You may use this file in accordance with the terms and conditions
|
|
13 |
** contained in the Technology Preview License Agreement accompanying
|
|
14 |
** this package.
|
|
15 |
**
|
|
16 |
** GNU Lesser General Public License Usage
|
|
17 |
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
18 |
** General Public License version 2.1 as published by the Free Software
|
|
19 |
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
20 |
** packaging of this file. Please review the following information to
|
|
21 |
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
22 |
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
23 |
**
|
|
24 |
** In addition, as a special exception, Nokia gives you certain additional
|
|
25 |
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
26 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
27 |
**
|
|
28 |
** If you have questions regarding the use of this file, please contact
|
|
29 |
** Nokia at qt-info@nokia.com.
|
|
30 |
**
|
|
31 |
**
|
|
32 |
**
|
|
33 |
**
|
|
34 |
**
|
|
35 |
**
|
|
36 |
**
|
|
37 |
**
|
|
38 |
** $QT_END_LICENSE$
|
|
39 |
**
|
|
40 |
****************************************************************************/
|
|
41 |
|
|
42 |
/*!
|
|
43 |
\example qws/svgalib
|
|
44 |
\title Accelerated Graphics Driver Example
|
|
45 |
|
|
46 |
The Accelerated Graphics Driver example shows how you can write
|
|
47 |
your own accelerated graphics driver and \l {add your graphics
|
|
48 |
driver to Qt for Embedded Linux}. In \l{Qt for Embedded Linux},
|
|
49 |
painting is a pure software implementation and is normally performed
|
|
50 |
in two steps:
|
|
51 |
The clients render each window onto a corresponding surface
|
|
52 |
(stored in memory) using a paint engine, and then the server uses
|
|
53 |
the graphics driver to compose the surface images and copy them to
|
|
54 |
the screen. (See the \l{Qt for Embedded Linux Architecture} documentation
|
|
55 |
for details.)
|
|
56 |
|
|
57 |
The rendering can be accelerated in two ways: Either by
|
|
58 |
accelerating the copying of pixels to the screen, or by
|
|
59 |
accelerating the explicit painting operations. The first is done
|
|
60 |
in the graphics driver implementation, the latter is performed by
|
|
61 |
the paint engine implementation. Typically, both the pixel copying
|
|
62 |
and the painting operations are accelerated using the following
|
|
63 |
approach:
|
|
64 |
|
|
65 |
\list 1
|
|
66 |
\o \l {Step 1: Creating a Custom Graphics Driver}
|
|
67 |
{Creating a Custom Graphics Driver}
|
|
68 |
|
|
69 |
\o \l {Step 2: Implementing a Custom Raster Paint Engine}
|
|
70 |
{Implementing a Custom Paint Engine}
|
|
71 |
|
|
72 |
\o \l {Step 3: Making the Widgets Aware of the Custom Paint
|
|
73 |
Engine}{Making the Widgets Aware of the Custom Paint Engine}
|
|
74 |
|
|
75 |
\endlist
|
|
76 |
|
|
77 |
After compiling the example code, install the graphics driver
|
|
78 |
plugin with the command \c {make install}. To start an application
|
|
79 |
using the graphics driver, you can either set the environment
|
|
80 |
variable \l QWS_DISPLAY and then run the application, or you can
|
|
81 |
just run the application using the \c -display switch:
|
|
82 |
|
|
83 |
\snippet doc/src/snippets/code/doc_src_examples_svgalib.qdoc 0
|
|
84 |
|
|
85 |
\table
|
|
86 |
\header \o SVGAlib
|
|
87 |
\row \o
|
|
88 |
|
|
89 |
Instead of interfacing the graphics hardware directly, this
|
|
90 |
example relies on \l {http://www.svgalib.org}{SVGAlib} being
|
|
91 |
installed on your system. \l {http://www.svgalib.org}{SVGAlib} is
|
|
92 |
a small graphics library which provides acceleration for many
|
|
93 |
common graphics cards used on desktop computers. It should work on
|
|
94 |
most workstations and has a small and simple API.
|
|
95 |
|
|
96 |
\endtable
|
|
97 |
|
|
98 |
\section1 Step 1: Creating a Custom Graphics Driver
|
|
99 |
|
|
100 |
The custom graphics driver is created by deriving from the QScreen
|
|
101 |
class. QScreen is the base class for implementing screen/graphics
|
|
102 |
drivers in Qt for Embedded Linux.
|
|
103 |
|
|
104 |
\snippet examples/qws/svgalib/svgalibscreen.h 0
|
|
105 |
\codeline
|
|
106 |
\snippet examples/qws/svgalib/svgalibscreen.h 1
|
|
107 |
|
|
108 |
The \l {QScreen::}{connect()}, \l {QScreen::}{disconnect()}, \l
|
|
109 |
{QScreen::}{initDevice()} and \l {QScreen::}{shutdownDevice()}
|
|
110 |
functions are declared as pure virtual functions in QScreen and
|
|
111 |
must be implemented. They are used to configure the hardware, or
|
|
112 |
query its configuration: \l {QScreen::}{connect()} and \l
|
|
113 |
{QScreen::}{disconnect()} are called by both the server and client
|
|
114 |
processes, while the \l {QScreen::}{initDevice()} and \l
|
|
115 |
{QScreen::}{shutdownDevice()} functions are only called by the
|
|
116 |
server process.
|
|
117 |
|
|
118 |
QScreen's \l {QScreen::}{setMode()} and \l {QScreen::}{blank()}
|
|
119 |
functions are also pure virtual, but our driver's implementations
|
|
120 |
are trivial. The last two functions (\l {QScreen::}{blit()} and \l
|
|
121 |
{QScreen::}{solidFill()}) are the ones involved in putting pixels
|
|
122 |
on the screen, i.e., we reimplement these functions to perform the
|
|
123 |
pixel copying acceleration.
|
|
124 |
|
|
125 |
Finally, the \c context variable is a pointer to a \l
|
|
126 |
{http://www.svgalib.org}{SVGAlib} specific type. Note that the
|
|
127 |
details of using the \l {http://www.svgalib.org}{SVGAlib} library
|
|
128 |
is beyond the scope of this example.
|
|
129 |
|
|
130 |
\section2 SvgalibScreen Class Implementation
|
|
131 |
|
|
132 |
The \l {QScreen::}{connect()} function is the first function that
|
|
133 |
is called after the constructor returns. It queries \l
|
|
134 |
{http://www.svgalib.org}{SVGAlib} about the graphics mode and
|
|
135 |
initializes the variables.
|
|
136 |
|
|
137 |
\snippet examples/qws/svgalib/svgalibscreen.cpp 0
|
|
138 |
|
|
139 |
It is important that the \l {QScreen::}{connect()} function
|
|
140 |
initializes the \c data, \c lstep, \c w, \c h, \c dw, \c dh, \c d,
|
|
141 |
\c physWidth and \c physHeight variables (inherited from QScreen)
|
|
142 |
to ensure that the driver is in a state consistent with the driver
|
|
143 |
configuration.
|
|
144 |
|
|
145 |
In this particular example we do not have any information of the
|
|
146 |
real physical size of the screen, so we set these values with the
|
|
147 |
assumption of a screen with 72 DPI.
|
|
148 |
|
|
149 |
\snippet examples/qws/svgalib/svgalibscreen.cpp 1
|
|
150 |
|
|
151 |
When the \l {QScreen::}{connect()} function returns, the server
|
|
152 |
process calls the \l {QScreen::}{initDevice()} function which is
|
|
153 |
expected to do the necessary hardware initialization, leaving the
|
|
154 |
hardware in a state consistent with the driver configuration.
|
|
155 |
|
|
156 |
Note that we have chosen to use the software cursor. If you want
|
|
157 |
to use a hardware cursor, you should create a subclass of
|
|
158 |
QScreenCursor, create an instance of it, and make the global
|
|
159 |
variable \c qt_screencursor point to this instance.
|
|
160 |
|
|
161 |
\snippet examples/qws/svgalib/svgalibscreen.cpp 2
|
|
162 |
\codeline
|
|
163 |
\snippet examples/qws/svgalib/svgalibscreen.cpp 3
|
|
164 |
|
|
165 |
Before exiting, the server process will call the \l
|
|
166 |
{QScreen::}{shutdownDevice()} function to do the necessary
|
|
167 |
hardware cleanup. Again, it is important that the function leaves
|
|
168 |
the hardware in a state consistent with the driver
|
|
169 |
configuration. When \l {QScreen::}{shutdownDevice()} returns, the
|
|
170 |
\l {QScreen::}{disconnect()} function is called. Our
|
|
171 |
implementation of the latter function is trivial.
|
|
172 |
|
|
173 |
Note that, provided that the \c QScreen::data variable points to a
|
|
174 |
valid linear framebuffer, the graphics driver is fully functional
|
|
175 |
as a simple screen driver at this point. The rest of this example
|
|
176 |
will show where to take advantage of the accelerated capabilities
|
|
177 |
available on the hardware.
|
|
178 |
|
|
179 |
Whenever an area on the screen needs to be updated, the server will
|
|
180 |
call the \l {QScreen::}{exposeRegion()} function that paints the
|
|
181 |
given region on screen. The default implementation will do the
|
|
182 |
necessary composing of the top-level windows and call \l
|
|
183 |
{QScreen::}{solidFill()} and \l {QScreen::}{blit()} whenever it is
|
|
184 |
required. We do not want to change this behavior in the driver so
|
|
185 |
we do not reimplement \l {QScreen::}{exposeRegion()}.
|
|
186 |
|
|
187 |
To control how the pixels are put onto the screen we need to
|
|
188 |
reimplement the \l {QScreen::}{solidFill()} and \l
|
|
189 |
{QScreen::}{blit()} functions.
|
|
190 |
|
|
191 |
\snippet examples/qws/svgalib/svgalibscreen.cpp 4
|
|
192 |
\codeline
|
|
193 |
\snippet examples/qws/svgalib/svgalibscreen.cpp 5
|
|
194 |
|
|
195 |
\section1 Step 2: Implementing a Custom Raster Paint Engine
|
|
196 |
|
|
197 |
\l{Qt for Embedded Linux} uses QRasterPaintEngine (a raster-based
|
|
198 |
implementation of QPaintEngine) to implement the painting
|
|
199 |
operations.
|
|
200 |
|
|
201 |
Acceleration of the painting operations is done by deriving from
|
|
202 |
QRasterPaintEngine class. This is a powerful mechanism for
|
|
203 |
accelerating graphic primitives while getting software fallbacks
|
|
204 |
for all the primitives you do not accelerate.
|
|
205 |
|
|
206 |
\snippet examples/qws/svgalib/svgalibpaintengine.h 0
|
|
207 |
|
|
208 |
In this example, we will only accelerate one of the \l
|
|
209 |
{QRasterPaintEngine::}{drawRects()} functions, i.e., only
|
|
210 |
non-rotated, aliased and opaque rectangles will be rendered using
|
|
211 |
accelerated painting. All other primitives are rendered using the
|
|
212 |
base class's unaccelerated implementation.
|
|
213 |
|
|
214 |
The paint engine's state is stored in the private member
|
|
215 |
variables, and we reimplement the \l
|
|
216 |
{QPaintEngine::}{updateState()} function to ensure that our
|
|
217 |
custom paint engine's state is updated properly whenever it is
|
|
218 |
required. The private \c setClip() and \c updateClip() functions
|
|
219 |
are only helper function used to simplify the \l
|
|
220 |
{QPaintEngine::}{updateState()} implementation.
|
|
221 |
|
|
222 |
We also reimplement QRasterPaintEngine's \l
|
|
223 |
{QRasterPaintEngine::}{begin()} and \l
|
|
224 |
{QRasterPaintEngine::}{end()} functions to initialize the paint
|
|
225 |
engine and to do the cleanup when we are done rendering,
|
|
226 |
respectively.
|
|
227 |
|
|
228 |
\table
|
|
229 |
\header \o Private Header Files
|
|
230 |
\row
|
|
231 |
\o
|
|
232 |
|
|
233 |
Note the \c include statement used by this class. The files
|
|
234 |
prefixed with \c private/ are private headers file within
|
|
235 |
\l{Qt for Embedded Linux}. Private header files are not part of
|
|
236 |
the standard installation and are only present while
|
|
237 |
compiling Qt. To be able to compile using
|
|
238 |
private header files you need to use a \c qmake binary within a
|
|
239 |
compiled \l{Qt for Embedded Linux} package.
|
|
240 |
|
|
241 |
\warning Private header files may change without notice between
|
|
242 |
releases.
|
|
243 |
|
|
244 |
\endtable
|
|
245 |
|
|
246 |
The \l {QRasterPaintEngine::}{begin()} function initializes the
|
|
247 |
internal state of the paint engine. Note that it also calls the
|
|
248 |
base class implementation to initialize the parts inherited from
|
|
249 |
QRasterPaintEngine:
|
|
250 |
|
|
251 |
\snippet examples/qws/svgalib/svgalibpaintengine.cpp 0
|
|
252 |
\codeline
|
|
253 |
\snippet examples/qws/svgalib/svgalibpaintengine.cpp 1
|
|
254 |
|
|
255 |
The implementation of the \l {QRasterPaintEngine::}{end()}
|
|
256 |
function removes the clipping constraints that might have been set
|
|
257 |
in \l {http://www.svgalib.org}{SVGAlib}, before calling the
|
|
258 |
corresponding base class implementation.
|
|
259 |
|
|
260 |
\snippet examples/qws/svgalib/svgalibpaintengine.cpp 2
|
|
261 |
|
|
262 |
The \l {QPaintEngine::}{updateState()} function updates our
|
|
263 |
custom paint engine's state. The QPaintEngineState class provides
|
|
264 |
information about the active paint engine's current state.
|
|
265 |
|
|
266 |
Note that we only accept and save the current matrix if it doesn't
|
|
267 |
do any shearing. The pen is accepted if it is opaque and only one
|
|
268 |
pixel wide. The rest of the engine's properties are updated
|
|
269 |
following the same pattern. Again it is important that the
|
|
270 |
QPaintEngine::updateState() function is called to update the
|
|
271 |
parts inherited from the base class.
|
|
272 |
|
|
273 |
\snippet examples/qws/svgalib/svgalibpaintengine.cpp 3
|
|
274 |
\codeline
|
|
275 |
\snippet examples/qws/svgalib/svgalibpaintengine.cpp 4
|
|
276 |
|
|
277 |
The \c setClip() helper function is called from our custom
|
|
278 |
implementation of \l {QPaintEngine::}{updateState()}, and
|
|
279 |
enables clipping to the given region. An empty region means that
|
|
280 |
clipping is disabled.
|
|
281 |
|
|
282 |
Our custom update function also makes use of the \c updateClip()
|
|
283 |
helper function that checks if the clip is "simple", i.e., that it
|
|
284 |
can be represented by only one rectangle, and updates the clip
|
|
285 |
region in \l {http://www.svgalib.org}{SVGAlib}.
|
|
286 |
|
|
287 |
\snippet examples/qws/svgalib/svgalibpaintengine.cpp 5
|
|
288 |
|
|
289 |
Finally, we accelerated that drawing of non-rotated, aliased and
|
|
290 |
opaque rectangles in our reimplementation of the \l
|
|
291 |
{QRasterPaintEngine::}{drawRects()} function. The
|
|
292 |
QRasterPaintEngine fallback is used whenever the rectangle is not
|
|
293 |
simple enough.
|
|
294 |
|
|
295 |
\section1 Step 3: Making the Widgets Aware of the Custom Paint Engine
|
|
296 |
|
|
297 |
To activate the custom paint engine, we also need to implement a
|
|
298 |
corresponding paint device and window surface and make some minor
|
|
299 |
adjustments of the graphics driver.
|
|
300 |
|
|
301 |
\list
|
|
302 |
\o \l {Implementing a Custom Paint Device}
|
|
303 |
\o \l {Implementing a Custom Window Surface}
|
|
304 |
\o \l {Adjusting the Graphics Driver}
|
|
305 |
\endlist
|
|
306 |
|
|
307 |
\section2 Implementing a Custom Paint Device
|
|
308 |
|
|
309 |
The custom paint device can be derived from the
|
|
310 |
QCustomRasterPaintDevice class. Reimplement its \l
|
|
311 |
{QCustomRasterPaintDevice::}{paintEngine()} and \l
|
|
312 |
{QCustomRasterPaintDevice::}{memory()} functions to activate the
|
|
313 |
accelerated paint engine:
|
|
314 |
|
|
315 |
\snippet examples/qws/svgalib/svgalibpaintdevice.h 0
|
|
316 |
|
|
317 |
The \l {QCustomRasterPaintDevice::}{paintEngine()} function should
|
|
318 |
return an instance of the \c SvgalibPaintEngine class. The \l
|
|
319 |
{QCustomRasterPaintDevice::}{memory()} function should return a
|
|
320 |
pointer to the buffer which should be used when drawing the
|
|
321 |
widget.
|
|
322 |
|
|
323 |
Our example driver is rendering directly to the screen without any
|
|
324 |
buffering, i.e., our custom pain device's \l
|
|
325 |
{QCustomRasterPaintDevice::}{memory()} function returns a pointer
|
|
326 |
to the framebuffer. For this reason, we must also reimplement the
|
|
327 |
\l {QPaintDevice::}{metric()} function to reflect the metrics of
|
|
328 |
framebuffer.
|
|
329 |
|
|
330 |
\section2 Implementing a Custom Window Surface
|
|
331 |
|
|
332 |
The custom window surface can be derived from the QWSWindowSurface
|
|
333 |
class. QWSWindowSurface manages the memory used when drawing a
|
|
334 |
window.
|
|
335 |
|
|
336 |
\snippet examples/qws/svgalib/svgalibsurface.h 0
|
|
337 |
|
|
338 |
We can implement most of the pure virtual functions inherited from
|
|
339 |
QWSWindowSurface as trivial inline functions, except the
|
|
340 |
\l {QWindowSurface::}{scroll()} function that actually makes use
|
|
341 |
of some hardware acceleration:
|
|
342 |
|
|
343 |
\snippet examples/qws/svgalib/svgalibsurface.cpp 0
|
|
344 |
|
|
345 |
\section2 Adjusting the Graphics Driver
|
|
346 |
|
|
347 |
Finally, we enable the graphics driver to recognize an instance of
|
|
348 |
our custom window surface:
|
|
349 |
|
|
350 |
\snippet examples/qws/svgalib/svgalibscreen.cpp 7
|
|
351 |
\codeline
|
|
352 |
\snippet examples/qws/svgalib/svgalibscreen.cpp 8
|
|
353 |
|
|
354 |
The \l {QScreen::}{createSurface()} functions are factory
|
|
355 |
functions that determines what kind of surface a top-level window
|
|
356 |
is using. In our example we only use the custom surface if the
|
|
357 |
given window has the Qt::WA_PaintOnScreen attribute or the
|
|
358 |
QT_ONSCREEN_PAINT environment variable is set.
|
|
359 |
*/
|
|
360 |
|