1 /****************************************************************************
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
6 ** This file is part of the documentation of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:FDL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
17 ** GNU Free Documentation License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Free
19 ** Documentation License version 1.3 as published by the Free Software
20 ** Foundation and appearing in the file included in the packaging of
21 ** this file. Please review the following information to ensure
22 ** the GNU Free Documentation License version 1.3 requirements
23 ** will be met: http://www.gnu.org/copyleft/fdl.html.
26 ****************************************************************************/
30 \title Accelerated Graphics Driver Example
32 \brief The Accelerated Graphics Driver example shows how you can write
33 your own accelerated graphics driver and \l {add your graphics
34 driver to Qt for Embedded Linux}.
36 In \l{Qt for Embedded Linux},
37 painting is a pure software implementation and is normally performed
39 The clients render each window onto a corresponding surface
40 (stored in memory) using a paint engine, and then the server uses
41 the graphics driver to compose the surface images and copy them to
42 the screen. (See the \l{Qt for Embedded Linux Architecture} documentation
45 The rendering can be accelerated in two ways: Either by
46 accelerating the copying of pixels to the screen, or by
47 accelerating the explicit painting operations. The first is done
48 in the graphics driver implementation, the latter is performed by
49 the paint engine implementation. Typically, both the pixel copying
50 and the painting operations are accelerated using the following
54 \o \l {Step 1: Creating a Custom Graphics Driver}
55 {Creating a Custom Graphics Driver}
57 \o \l {Step 2: Implementing a Custom Raster Paint Engine}
58 {Implementing a Custom Paint Engine}
60 \o \l {Step 3: Making the Widgets Aware of the Custom Paint
61 Engine}{Making the Widgets Aware of the Custom Paint Engine}
65 After compiling the example code, install the graphics driver
66 plugin with the command \c {make install}. To start an application
67 using the graphics driver, you can either set the environment
68 variable \l QWS_DISPLAY and then run the application, or you can
69 just run the application using the \c -display switch:
71 \snippet doc/src/snippets/code/doc_src_examples_svgalib.qdoc 0
77 Instead of interfacing the graphics hardware directly, this
78 example relies on \l {http://www.svgalib.org}{SVGAlib} being
79 installed on your system. \l {http://www.svgalib.org}{SVGAlib} is
80 a small graphics library which provides acceleration for many
81 common graphics cards used on desktop computers. It should work on
82 most workstations and has a small and simple API.
86 \section1 Step 1: Creating a Custom Graphics Driver
88 The custom graphics driver is created by deriving from the QScreen
89 class. QScreen is the base class for implementing screen/graphics
90 drivers in Qt for Embedded Linux.
92 \snippet examples/qws/svgalib/svgalibscreen.h 0
94 \snippet examples/qws/svgalib/svgalibscreen.h 1
96 The \l {QScreen::}{connect()}, \l {QScreen::}{disconnect()}, \l
97 {QScreen::}{initDevice()} and \l {QScreen::}{shutdownDevice()}
98 functions are declared as pure virtual functions in QScreen and
99 must be implemented. They are used to configure the hardware, or
100 query its configuration: \l {QScreen::}{connect()} and \l
101 {QScreen::}{disconnect()} are called by both the server and client
102 processes, while the \l {QScreen::}{initDevice()} and \l
103 {QScreen::}{shutdownDevice()} functions are only called by the
106 QScreen's \l {QScreen::}{setMode()} and \l {QScreen::}{blank()}
107 functions are also pure virtual, but our driver's implementations
108 are trivial. The last two functions (\l {QScreen::}{blit()} and \l
109 {QScreen::}{solidFill()}) are the ones involved in putting pixels
110 on the screen, i.e., we reimplement these functions to perform the
111 pixel copying acceleration.
113 Finally, the \c context variable is a pointer to a \l
114 {http://www.svgalib.org}{SVGAlib} specific type. Note that the
115 details of using the \l {http://www.svgalib.org}{SVGAlib} library
116 is beyond the scope of this example.
118 \section2 SvgalibScreen Class Implementation
120 The \l {QScreen::}{connect()} function is the first function that
121 is called after the constructor returns. It queries \l
122 {http://www.svgalib.org}{SVGAlib} about the graphics mode and
123 initializes the variables.
125 \snippet examples/qws/svgalib/svgalibscreen.cpp 0
127 It is important that the \l {QScreen::}{connect()} function
128 initializes the \c data, \c lstep, \c w, \c h, \c dw, \c dh, \c d,
129 \c physWidth and \c physHeight variables (inherited from QScreen)
130 to ensure that the driver is in a state consistent with the driver
133 In this particular example we do not have any information of the
134 real physical size of the screen, so we set these values with the
135 assumption of a screen with 72 DPI.
137 \snippet examples/qws/svgalib/svgalibscreen.cpp 1
139 When the \l {QScreen::}{connect()} function returns, the server
140 process calls the \l {QScreen::}{initDevice()} function which is
141 expected to do the necessary hardware initialization, leaving the
142 hardware in a state consistent with the driver configuration.
144 Note that we have chosen to use the software cursor. If you want
145 to use a hardware cursor, you should create a subclass of
146 QScreenCursor, create an instance of it, and make the global
147 variable \c qt_screencursor point to this instance.
149 \snippet examples/qws/svgalib/svgalibscreen.cpp 2
151 \snippet examples/qws/svgalib/svgalibscreen.cpp 3
153 Before exiting, the server process will call the \l
154 {QScreen::}{shutdownDevice()} function to do the necessary
155 hardware cleanup. Again, it is important that the function leaves
156 the hardware in a state consistent with the driver
157 configuration. When \l {QScreen::}{shutdownDevice()} returns, the
158 \l {QScreen::}{disconnect()} function is called. Our
159 implementation of the latter function is trivial.
161 Note that, provided that the \c QScreen::data variable points to a
162 valid linear framebuffer, the graphics driver is fully functional
163 as a simple screen driver at this point. The rest of this example
164 will show where to take advantage of the accelerated capabilities
165 available on the hardware.
167 Whenever an area on the screen needs to be updated, the server will
168 call the \l {QScreen::}{exposeRegion()} function that paints the
169 given region on screen. The default implementation will do the
170 necessary composing of the top-level windows and call \l
171 {QScreen::}{solidFill()} and \l {QScreen::}{blit()} whenever it is
172 required. We do not want to change this behavior in the driver so
173 we do not reimplement \l {QScreen::}{exposeRegion()}.
175 To control how the pixels are put onto the screen we need to
176 reimplement the \l {QScreen::}{solidFill()} and \l
177 {QScreen::}{blit()} functions.
179 \snippet examples/qws/svgalib/svgalibscreen.cpp 4
181 \snippet examples/qws/svgalib/svgalibscreen.cpp 5
183 \section1 Step 2: Implementing a Custom Raster Paint Engine
185 \l{Qt for Embedded Linux} uses QRasterPaintEngine (a raster-based
186 implementation of QPaintEngine) to implement the painting
189 Acceleration of the painting operations is done by deriving from
190 QRasterPaintEngine class. This is a powerful mechanism for
191 accelerating graphic primitives while getting software fallbacks
192 for all the primitives you do not accelerate.
194 \snippet examples/qws/svgalib/svgalibpaintengine.h 0
196 In this example, we will only accelerate one of the \l
197 {QRasterPaintEngine::}{drawRects()} functions, i.e., only
198 non-rotated, aliased and opaque rectangles will be rendered using
199 accelerated painting. All other primitives are rendered using the
200 base class's unaccelerated implementation.
202 The paint engine's state is stored in the private member
203 variables, and we reimplement the \l
204 {QPaintEngine::}{updateState()} function to ensure that our
205 custom paint engine's state is updated properly whenever it is
206 required. The private \c setClip() and \c updateClip() functions
207 are only helper function used to simplify the \l
208 {QPaintEngine::}{updateState()} implementation.
210 We also reimplement QRasterPaintEngine's \l
211 {QRasterPaintEngine::}{begin()} and \l
212 {QRasterPaintEngine::}{end()} functions to initialize the paint
213 engine and to do the cleanup when we are done rendering,
217 \header \o Private Header Files
221 Note the \c include statement used by this class. The files
222 prefixed with \c private/ are private headers file within
223 \l{Qt for Embedded Linux}. Private header files are not part of
224 the standard installation and are only present while
225 compiling Qt. To be able to compile using
226 private header files you need to use a \c qmake binary within a
227 compiled \l{Qt for Embedded Linux} package.
229 \warning Private header files may change without notice between
234 The \l {QRasterPaintEngine::}{begin()} function initializes the
235 internal state of the paint engine. Note that it also calls the
236 base class implementation to initialize the parts inherited from
239 \snippet examples/qws/svgalib/svgalibpaintengine.cpp 0
241 \snippet examples/qws/svgalib/svgalibpaintengine.cpp 1
243 The implementation of the \l {QRasterPaintEngine::}{end()}
244 function removes the clipping constraints that might have been set
245 in \l {http://www.svgalib.org}{SVGAlib}, before calling the
246 corresponding base class implementation.
248 \snippet examples/qws/svgalib/svgalibpaintengine.cpp 2
250 The \l {QPaintEngine::}{updateState()} function updates our
251 custom paint engine's state. The QPaintEngineState class provides
252 information about the active paint engine's current state.
254 Note that we only accept and save the current matrix if it doesn't
255 do any shearing. The pen is accepted if it is opaque and only one
256 pixel wide. The rest of the engine's properties are updated
257 following the same pattern. Again it is important that the
258 QPaintEngine::updateState() function is called to update the
259 parts inherited from the base class.
261 \snippet examples/qws/svgalib/svgalibpaintengine.cpp 3
263 \snippet examples/qws/svgalib/svgalibpaintengine.cpp 4
265 The \c setClip() helper function is called from our custom
266 implementation of \l {QPaintEngine::}{updateState()}, and
267 enables clipping to the given region. An empty region means that
268 clipping is disabled.
270 Our custom update function also makes use of the \c updateClip()
271 helper function that checks if the clip is "simple", i.e., that it
272 can be represented by only one rectangle, and updates the clip
273 region in \l {http://www.svgalib.org}{SVGAlib}.
275 \snippet examples/qws/svgalib/svgalibpaintengine.cpp 5
277 Finally, we accelerated that drawing of non-rotated, aliased and
278 opaque rectangles in our reimplementation of the \l
279 {QRasterPaintEngine::}{drawRects()} function. The
280 QRasterPaintEngine fallback is used whenever the rectangle is not
283 \section1 Step 3: Making the Widgets Aware of the Custom Paint Engine
285 To activate the custom paint engine, we also need to implement a
286 corresponding paint device and window surface and make some minor
287 adjustments of the graphics driver.
290 \o \l {Implementing a Custom Paint Device}
291 \o \l {Implementing a Custom Window Surface}
292 \o \l {Adjusting the Graphics Driver}
295 \section2 Implementing a Custom Paint Device
297 The custom paint device can be derived from the
298 QCustomRasterPaintDevice class. Reimplement its \l
299 {QCustomRasterPaintDevice::}{paintEngine()} and \l
300 {QCustomRasterPaintDevice::}{memory()} functions to activate the
301 accelerated paint engine:
303 \snippet examples/qws/svgalib/svgalibpaintdevice.h 0
305 The \l {QCustomRasterPaintDevice::}{paintEngine()} function should
306 return an instance of the \c SvgalibPaintEngine class. The \l
307 {QCustomRasterPaintDevice::}{memory()} function should return a
308 pointer to the buffer which should be used when drawing the
311 Our example driver is rendering directly to the screen without any
312 buffering, i.e., our custom pain device's \l
313 {QCustomRasterPaintDevice::}{memory()} function returns a pointer
314 to the framebuffer. For this reason, we must also reimplement the
315 \l {QPaintDevice::}{metric()} function to reflect the metrics of
318 \section2 Implementing a Custom Window Surface
320 The custom window surface can be derived from the QWSWindowSurface
321 class. QWSWindowSurface manages the memory used when drawing a
324 \snippet examples/qws/svgalib/svgalibsurface.h 0
326 We can implement most of the pure virtual functions inherited from
327 QWSWindowSurface as trivial inline functions, except the scroll()
328 function that actually makes use of some hardware acceleration:
330 \snippet examples/qws/svgalib/svgalibsurface.cpp 0
332 \section2 Adjusting the Graphics Driver
334 Finally, we enable the graphics driver to recognize an instance of
335 our custom window surface:
337 \snippet examples/qws/svgalib/svgalibscreen.cpp 7
339 \snippet examples/qws/svgalib/svgalibscreen.cpp 8
341 The \l {QScreen::}{createSurface()} functions are factory
342 functions that determines what kind of surface a top-level window
343 is using. In our example we only use the custom surface if the
344 given window has the Qt::WA_PaintOnScreen attribute or the
345 QT_ONSCREEN_PAINT environment variable is set.