http://www.wiki.crossplatform.ru/index.php?title=Qt:%D0%94%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0%D1%86%D0%B8%D1%8F_4.3.2/qtopiacore-svgalib&feed=atom&action=historyQt:Документация 4.3.2/qtopiacore-svgalib - История изменений2024-03-29T10:54:30ZИстория изменений этой страницы в викиMediaWiki 1.15.1http://www.wiki.crossplatform.ru/index.php?title=Qt:%D0%94%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0%D1%86%D0%B8%D1%8F_4.3.2/qtopiacore-svgalib&diff=4981&oldid=prevRoot: Новая: {{Qt4.3.2_header}} =Accelerated Graphics Driver Example<br />= Файлы: *[[Qt:Документация 4.3.2/qtopiacore-svgalib-svgalibpaintdevice-cpp | qtopiacore/svgalib/svgalibp...2009-01-29T10:33:22Z<p>Новая: {{Qt4.3.2_header}} =Accelerated Graphics Driver Example<br />= Файлы: *[[Qt:Документация 4.3.2/qtopiacore-svgalib-svgalibpaintdevice-cpp | qtopiacore/svgalib/svgalibp...</p>
<p><b>Новая страница</b></p><div>{{Qt4.3.2_header}}<br />
<br />
=Accelerated Graphics Driver Example<br />=<br />
<br />
Файлы:<br />
<br />
*[[Qt:Документация 4.3.2/qtopiacore-svgalib-svgalibpaintdevice-cpp | qtopiacore/svgalib/svgalibpaintdevice.cpp]]<br />
*[[Qt:Документация 4.3.2/qtopiacore-svgalib-svgalibpaintdevice-h | qtopiacore/svgalib/svgalibpaintdevice.h]]<br />
*[[Qt:Документация 4.3.2/qtopiacore-svgalib-svgalibpaintengine-cpp | qtopiacore/svgalib/svgalibpaintengine.cpp]]<br />
*[[Qt:Документация 4.3.2/qtopiacore-svgalib-svgalibpaintengine-h | qtopiacore/svgalib/svgalibpaintengine.h]]<br />
*[[Qt:Документация 4.3.2/qtopiacore-svgalib-svgalibplugin-cpp | qtopiacore/svgalib/svgalibplugin.cpp]]<br />
*[[Qt:Документация 4.3.2/qtopiacore-svgalib-svgalibscreen-cpp | qtopiacore/svgalib/svgalibscreen.cpp]]<br />
*[[Qt:Документация 4.3.2/qtopiacore-svgalib-svgalibscreen-h | qtopiacore/svgalib/svgalibscreen.h]]<br />
*[[Qt:Документация 4.3.2/qtopiacore-svgalib-svgalibsurface-cpp | qtopiacore/svgalib/svgalibsurface.cpp]]<br />
*[[Qt:Документация 4.3.2/qtopiacore-svgalib-svgalibsurface-h | qtopiacore/svgalib/svgalibsurface.h]]<br />
<br />
The Accelerated Graphics Driver example shows how you can write your own accelerated graphics driver and [[Qt:Документация 4.3.2/qtopiacore-accel#add-your-graphics-driver-to-qtopia-core | add your graphics driver to Qtopia Core]]. In [[Qt:Документация 4.3.2/qtopiacore | Qtopia Core]], painting is a pure software implementation and is normally performed in two steps: The clients render each window onto a corresponding surface (stored in memory) using a paint engine, and then the server uses the graphics driver to compose the surface images and copy them to the screen. (See the [[Qt:Документация 4.3.2/qtopiacore-architecture | Qtopia Core Architecture]] documentation for details.)<br />
<br />
The rendering can be accelerated in two ways: Either by accelerating the copying of pixels to the screen, or by accelerating the explicit painting operations. The first is done in the graphics driver implementation, the latter is performed by the paint engine implementation. Typically, both the pixel copying and the painting operations are accelerted using the following approach:<br />
<br />
#[[#step-1-creating-a-custom-graphics-driver | Creating a Custom Graphics Driver]]<br />
#[[#step-2-implementing-a-custom-raster-paint-engine | Implementing a Custom Paint Engine]]<br />
#[[#step-3-making-the-widgets-aware-of-the-custom-paint-engine | Making the Widgets Aware of the Custom Paint Engine]]<br />
<br />
After compiling the example code, install the graphics driver plugin with the command <tt>make install</tt>. To start an application using the graphics driver, you can either set the environment variable [[Qt:Документация 4.3.2/qtopiacore-envvars#qws-display | QWS_DISPLAY]] and then run the application, or you can just run the application using the <tt>-display</tt> switch:<br />
<source lang="cpp-qt"> myApplication -qws -display svgalib</source> <br />
Note that in order to keep the example as simple as possible, our driver only works with screen modes having 32 bits per pixel and does not work with multiple processes.<br />
<br />
<br />
{| align="center" cellpadding="2" cellspacing="1" border="0"<br />
<br />
|- valign="top" class="qt-style" | <br />
!SVGAlib<br />
|- valign="top" class="odd" | <br />
|Instead of interfacing the graphics hardware directly, this example relies on [http://www.svgalib.org SVGAlib] being installed on your system. [http://www.svgalib.org SVGAlib] is a small graphics library which provides acceleration for many common graphics cards used on desktop computers. It should work on most workstations and has a small and simple API.<br />
|}<br />
<div id="step-1-creating-a-custom-graphics-driver"></div><br />
==Step 1: Creating a Custom Graphics Driver==<br />
<br />
The custom graphics driver is created by deriving from the [[Qt:Документация 4.3.2/qscreen | QScreen]] class. [[Qt:Документация 4.3.2/qscreen | QScreen]] is the base class for implementing screen/graphics drivers in Qtopia Core.<br />
<source lang="cpp-qt"> class SvgalibScreen : public QScreen<br />
{<br />
public:<br />
SvgalibScreen(int displayId) : QScreen(displayId) {}<br />
~SvgalibScreen() {}<br />
<br />
bool connect(const QString &amp;displaySpec);<br />
bool initDevice();<br />
void shutdownDevice();<br />
void disconnect();<br />
<br />
void setMode(int, int, int) {}<br />
void blank(bool) {}<br />
<br />
void exposeRegion(QRegion r, int changing);<br />
void blit(const QImage &amp;img, const QPoint &amp;topLeft, const QRegion &amp;region);<br />
void solidFill(const QColor &amp;color, const QRegion &amp;region);<br />
<br />
private:<br />
GraphicsContext *context;<br />
};</source> <br />
The [[Qt:Документация 4.3.2/qscreen#connect | connect()]], [[Qt:Документация 4.3.2/qscreen#disconnect | disconnect()]], [[Qt:Документация 4.3.2/qscreen#initDevice | initDevice()]] and [[Qt:Документация 4.3.2/qscreen#shutdownDevice | shutdownDevice()]] functions are declared as pure virtual functions in [[Qt:Документация 4.3.2/qscreen | QScreen]] and must be implemented. They are used to configure the hardware, or query its configuration: [[Qt:Документация 4.3.2/qscreen#connect | connect()]] and [[Qt:Документация 4.3.2/qscreen#disconnect | disconnect()]] are called by both the server and client processes, while the [[Qt:Документация 4.3.2/qscreen#initDevice | initDevice()]] and [[Qt:Документация 4.3.2/qscreen#shutdownDevice | shutdownDevice()]] functions are only called by the server process.<br />
<br />
[[Qt:Документация 4.3.2/qscreen | QScreen]]'s [[Qt:Документация 4.3.2/qscreen#setMode | setMode()]] and [[Qt:Документация 4.3.2/qscreen#blank | blank()]] functions are also pure virtual, but our driver's implementations are trivial. The last three functions ([[Qt:Документация 4.3.2/qscreen#exposeRegion | exposeRegion()]], [[Qt:Документация 4.3.2/qscreen#blit | blit()]] and [[Qt:Документация 4.3.2/qscreen#solidFill | solidFill()]]) are the ones involved in putting pixels on the screen, i.e., we reimplement these functions to perform the pixel copying acceleration.<br />
<br />
Finally, the <tt>context</tt> variable is a pointer to a [http://www.svgalib.org SVGAlib] specific type. Note that the details of using the [http://www.svgalib.org SVGAlib] library is beyond the scope of this example.<br />
<div id="svgalibscreen-class-implementation"></div><br />
===SvgalibScreen Class Implementation===<br />
<br />
The [[Qt:Документация 4.3.2/qscreen#connect | connect()]] function is the first function that is called after the constructor returns. It queries [http://www.svgalib.org SVGAlib] about the graphics mode and initializes the variables.<br />
<source lang="cpp-qt"> bool SvgalibScreen::connect(const QString &amp;displaySpec)<br />
{<br />
Q_UNUSED(displaySpec);<br />
<br />
int mode = vga_getdefaultmode();<br />
if (mode <= 0) {<br />
qCritical("SvgalibScreen::connect(): invalid vga mode");<br />
return false;<br />
}<br />
<br />
vga_modeinfo *modeinfo = vga_getmodeinfo(mode);<br />
<br />
QScreen::lstep = modeinfo->linewidth;<br />
QScreen::dw = QScreen::w = modeinfo->width;<br />
QScreen::dh = QScreen::h = modeinfo->height;<br />
QScreen::d = modeinfo->bytesperpixel * 8;<br />
QScreen::size = QScreen::lstep * dh;<br />
QScreen::data = 0;<br />
<br />
switch (depth()) {<br />
case 32:<br />
setPixelFormat(QImage::Format_ARGB32_Premultiplied);<br />
break;<br />
case 16:<br />
setPixelFormat(QImage::Format_RGB16);<br />
break;<br />
default:<br />
break;<br />
}<br />
<br />
const int dpi = 72;<br />
QScreen::physWidth = qRound(QScreen::dw * 25.4 / dpi);<br />
QScreen::physHeight = qRound(QScreen::dh * 25.4 / dpi);<br />
<br />
return true;<br />
}</source> <br />
It is important that the [[Qt:Документация 4.3.2/qscreen#connect | connect()]] function initializes the <tt>data</tt>, <tt>lstep</tt>, <tt>w</tt>, <tt>h</tt>, <tt>dw</tt>, <tt>dh</tt>, <tt>d</tt>, <tt>physWidth</tt> and <tt>physHeight</tt> variables (inherited from [[Qt:Документация 4.3.2/qscreen | QScreen]]) to ensure that the driver is in a state consistent with the driver configuration.<br />
<br />
In this particular example we do not have any information of the real physical size of the screen, so we set these values with the assumption of a screen with 72 DPI.<br />
<source lang="cpp-qt"> bool SvgalibScreen::initDevice()<br />
{<br />
if (vga_init() != 0) {<br />
qCritical("SvgalibScreen::initDevice(): unable to initialize svgalib");<br />
return false;<br />
}<br />
<br />
int mode = vga_getdefaultmode();<br />
if (vga_setmode(mode) == -1) {<br />
qCritical("SvgalibScreen::initialize(): unable to set graphics mode");<br />
return false;<br />
}<br />
<br />
if (gl_setcontextvga(mode) != 0) {<br />
qCritical("SvgalibScreen::initDevice(): unable to set vga context");<br />
return false;<br />
}<br />
context = gl_allocatecontext();<br />
gl_getcontext(context);<br />
<br />
vga_modeinfo *modeinfo = vga_getmodeinfo(mode);<br />
if (modeinfo->flags &amp; IS_LINEAR)<br />
QScreen::data = vga_getgraphmem();<br />
<br />
QScreenCursor::initSoftwareCursor();<br />
return true;<br />
}</source> <br />
When the [[Qt:Документация 4.3.2/qscreen#connect | connect()]] function returns, the server process calls the [[Qt:Документация 4.3.2/qscreen#initDevice | initDevice()]] function which is expected to do the necessary hardware initialization, leaving the hardware in a state consistent with the driver configuration.<br />
<br />
Note that we have chosen to use the software cursor. If you want to use a hardware cursor, you should create a subclass of [[Qt:Документация 4.3.2/qscreencursor | QScreenCursor]], create an instance of it, and make the global variable <tt>qt_screencursor</tt> point to this instance.<br />
<source lang="cpp-qt"> void SvgalibScreen::shutdownDevice()<br />
{<br />
gl_freecontext(context);<br />
vga_setmode(TEXT);<br />
}<br />
<br />
void SvgalibScreen::disconnect()<br />
{<br />
}</source> <br />
Before exiting, the server process will call the [[Qt:Документация 4.3.2/qscreen#shutdownDevice | shutdownDevice()]] function to do the necessary hardware cleanup. Again, it is important that the function leaves the hardware in a state consistent with the driver configuration. When [[Qt:Документация 4.3.2/qscreen#shutdownDevice | shutdownDevice()]] returns, the [[Qt:Документация 4.3.2/qscreen#disconnect | disconnect()]] function is called. Our implementation of the latter function is trivial.<br />
<br />
Note that, provided that the <tt>QScreen::data</tt> variable points to a valid linear framebuffer, the graphics driver is fully functional as a simple screen driver at this point. The rest of this example will show where to take advantage of the accelerated capabilities available on the hardware.<br />
<source lang="cpp-qt"> void SvgalibScreen::exposeRegion(QRegion region, int changing)<br />
{<br />
QScreen::exposeRegion(region, changing);<br />
// flip between buffers if implementing a double buffered driver<br />
}</source> <br />
The next function we implement is the [[Qt:Документация 4.3.2/qscreen#exposeRegion | exposeRegion()]] function that paints the given region on screen.<br />
<br />
The default implementation will do the necessary composing of the top-level windows and call [[Qt:Документация 4.3.2/qscreen#solidFill | solidFill()]] and [[Qt:Документация 4.3.2/qscreen#blit | blit()]] whenever it is required. We do not want to change this behavior in this driver so we just call the base class implementation. On the other hand, if you are implementing a double buffered screen driver, this is where you would like to flip between the buffers.<br />
<source lang="cpp-qt"> void SvgalibScreen::solidFill(const QColor &amp;color, const QRegion &amp;reg)<br />
{<br />
if (depth() != 32 &amp;&amp; depth() != 16) {<br />
if (base())<br />
QScreen::solidFill(color, reg);<br />
return;<br />
}<br />
<br />
const QVector<QRect> rects = (reg &amp; region()).rects();<br />
for (int i = 0; i < rects.size(); ++i) {<br />
const QRect r = rects.at(i);<br />
gl_fillbox(r.left(), r.top(), r.width(), r.height(), color.rgba());<br />
}<br />
}<br />
<br />
void SvgalibScreen::blit(const QImage &amp;img, const QPoint &amp;topLeft,<br />
const QRegion &amp;reg)<br />
{<br />
if (img.format() != pixelFormat()) {<br />
if (base())<br />
QScreen::blit(img, topLeft, reg);<br />
return;<br />
}<br />
<br />
const QVector<QRect> rects = (reg &amp; region()).rects();<br />
<br />
for (int i = 0; i < rects.size(); ++i) {<br />
const QRect r = rects.at(i);<br />
gl_putboxpart(r.x(), r.y(), r.width(), r.height(),<br />
img.width(), img.height(),<br />
static_cast<void*>(const_cast<uchar*>(img.bits())),<br />
r.x() - topLeft.x(), r.y() - topLeft.y());<br />
}<br />
}</source> <br />
Finally, we accelerate the copying of pixels to the screen by reimplementing the [[Qt:Документация 4.3.2/qscreen#solidFill | solidFill()]] and [[Qt:Документация 4.3.2/qscreen#blit | blit()]] functions.<br />
<div id="step-2-implementing-a-custom-raster-paint-engine"></div><br />
==Step 2: Implementing a Custom Raster Paint Engine==<br />
<br />
[[Qt:Документация 4.3.2/qtopiacore | Qtopia Core]] uses [[Qt:Документация 4.3.2/qrasterpaintengine | QRasterPaintEngine]] (a raster-based implementation of [[Qt:Документация 4.3.2/qpaintengine | QPaintEngine]]) to implement the painting operations.<br />
<br />
Acceleration of the painting operations is done by deriving from [[Qt:Документация 4.3.2/qrasterpaintengine | QRasterPaintEngine]] class. This is a powerful mechanism for accelerating graphic primitives while getting software fallbacks for all the primitives you do not accelerate.<br />
<source lang="cpp-qt"> #include <private/qpaintengine_raster_p.h><br />
<br />
class SvgalibPaintEngine : public QRasterPaintEngine<br />
{<br />
public:<br />
SvgalibPaintEngine();<br />
~SvgalibPaintEngine();<br />
<br />
bool begin(QPaintDevice *device);<br />
bool end();<br />
void updateState(const QPaintEngineState &amp;state);<br />
void drawRects(const QRect *rects, int rectCount);<br />
<br />
private:<br />
void setClip(const QRegion &amp;region);<br />
void updateClip();<br />
<br />
QPen pen;<br />
bool simplePen;<br />
QBrush brush;<br />
bool simpleBrush;<br />
QMatrix matrix;<br />
bool simpleMatrix;<br />
QRegion clip;<br />
bool clipEnabled;<br />
bool simpleClip;<br />
bool opaque;<br />
bool aliased;<br />
bool sourceOver;<br />
QPaintDevice *device;<br />
};</source> <br />
In this example, we will only accelerate one of the [[Qt:Документация 4.3.2/qpaintengine#drawRects-2 | drawRects()]] functions, i.e., only non-rotated, aliased and opaque rectangles will be rendered using accelerated painting. All other primitives are rendered using the base class's unaccelerated implementation.<br />
<br />
The paint engine's state is stored in the private member variables, and we reimplement the [[Qt:Документация 4.3.2/qpaintengine#updateState | updateState()]] function to ensure that our custom paint engine's state is updated properly whenever it is required. The private <tt>setClip()</tt> and <tt>updateClip()</tt> functions are only helper function used to simplify the [[Qt:Документация 4.3.2/qpaintengine#updateState | updateState()]] implementation.<br />
<br />
We also reimplement [[Qt:Документация 4.3.2/qrasterpaintengine | QRasterPaintEngine]]'s [[Qt:Документация 4.3.2/qpaintengine#begin | begin()]] and [[Qt:Документация 4.3.2/qpaintengine#end | end()]] functions to initialize the paint engine and to do the cleanup when we are done rendering, respectively.<br />
<br />
<br />
{| align="center" cellpadding="2" cellspacing="1" border="0"<br />
<br />
|- valign="top" class="qt-style" | <br />
!Private Header Files<br />
|- valign="top" class="odd" | <br />
|Note the <tt>include</tt> statement used by this class. The files prefixed with <tt>private/</tt> are private headers file within [[Qt:Документация 4.3.2/qtopiacore | Qtopia Core]]. Private header files are not part of a [[Qt:Документация 4.3.2/qtopiacore | Qtopia Core]] installation and are only present while compiling [[Qt:Документация 4.3.2/qtopiacore | Qtopia Core]]. To be able to compile using private header files you need to use a <tt>qmake</tt> binary within a compiled [[Qt:Документация 4.3.2/qtopiacore | Qtopia Core]] package.<br />
'''Warning:''' Private header files may change without notice between releases.<br />
<br />
|}<br />
<br />
The [[Qt:Документация 4.3.2/qpaintengine#begin | begin()]] function initializes the internal state of the paint engine. Note that it also calls the base class implementation to initialize the parts inherited from [[Qt:Документация 4.3.2/qrasterpaintengine | QRasterPaintEngine]]:<br />
<source lang="cpp-qt"> bool SvgalibPaintEngine::begin(QPaintDevice *dev)<br />
{<br />
device = dev;<br />
pen = Qt::NoPen;<br />
simplePen = true;<br />
brush = Qt::NoBrush;<br />
simpleBrush = true;<br />
matrix = QMatrix();<br />
simpleMatrix = true;<br />
setClip(QRect(0, 0, device->width(), device->height()));<br />
opaque = true;<br />
aliased = true;<br />
sourceOver = true;<br />
<br />
return QRasterPaintEngine::begin(dev);<br />
}<br />
<br />
bool SvgalibPaintEngine::end()<br />
{<br />
gl_setclippingwindow(0, 0, device->width() - 1, device->height() - 1);<br />
return QRasterPaintEngine::end();<br />
}</source> <br />
The implementation of the [[Qt:Документация 4.3.2/qpaintengine#end | end()]] function removes the clipping constraints that might have been set in [http://www.svgalib.org SVGAlib], before calling the corresponding base class implementation.<br />
<source lang="cpp-qt"> void SvgalibPaintEngine::updateState(const QPaintEngineState &amp;state)<br />
{<br />
QPaintEngine::DirtyFlags flags = state.state();<br />
<br />
if (flags &amp; DirtyTransform) {<br />
matrix = state.matrix();<br />
simpleMatrix = (matrix.m12() == 0 &amp;&amp; matrix.m21() == 0);<br />
}<br />
<br />
if (flags &amp; DirtyPen) {<br />
pen = state.pen();<br />
simplePen = (pen.width() == 0 || pen.widthF() <= 1)<br />
&amp;&amp; (pen.style() == Qt::NoPen || pen.style() == Qt::SolidLine)<br />
&amp;&amp; (pen.color().alpha() == 255);<br />
}<br />
<br />
if (flags &amp; DirtyBrush) {<br />
brush = state.brush();<br />
simpleBrush = (brush.style() == Qt::SolidPattern<br />
|| brush.style() == Qt::NoBrush)<br />
&amp;&amp; (brush.color().alpha() == 255);<br />
}<br />
<br />
if (flags &amp; DirtyClipRegion)<br />
setClip(state.clipRegion());<br />
<br />
if (flags &amp; DirtyClipEnabled) {<br />
clipEnabled = state.isClipEnabled();<br />
updateClip();<br />
}<br />
<br />
if (flags &amp; DirtyClipPath) {<br />
setClip(QRegion());<br />
simpleClip = false;<br />
}<br />
<br />
if (flags &amp; DirtyCompositionMode) {<br />
const QPainter::CompositionMode m = state.compositionMode();<br />
sourceOver = (m == QPainter::CompositionMode_SourceOver);<br />
}<br />
<br />
if (flags &amp; DirtyOpacity)<br />
opaque = (state.opacity() == 256);<br />
<br />
if (flags &amp; DirtyHints)<br />
aliased = !(state.renderHints() &amp; QPainter::Antialiasing);<br />
<br />
QRasterPaintEngine::updateState(state);<br />
}</source> <br />
The [[Qt:Документация 4.3.2/qpaintengine#updateState | updateState()]] function updates our custom paint engine's state. The [[Qt:Документация 4.3.2/qpaintenginestate | QPaintEngineState]] class provides information about the active paint engine's current state.<br />
<br />
Note that we only accept and save the current matrix if it doesn't do any shearing. The pen is accepted if it is opaque and only one pixel wide. The rest of the engine's properties are updated following the same pattern. Again it is important that the [[Qt:Документация 4.3.2/qpaintengine#updateState | QRasterPaintEngine::updateState]]() function is called to update the parts inherited from the base class.<br />
<source lang="cpp-qt"> void SvgalibPaintEngine::setClip(const QRegion &amp;region)<br />
{<br />
if (region.isEmpty())<br />
clip = QRect(0, 0, device->width(), device->height());<br />
else<br />
clip = matrix.map(region) &amp; QRect(0, 0, device->width(), device->height());<br />
clipEnabled = true;<br />
updateClip();<br />
}<br />
<br />
void SvgalibPaintEngine::updateClip()<br />
{<br />
QRegion clipRegion = QRect(0, 0, device->width(), device->height());<br />
<br />
if (!systemClip().isEmpty())<br />
clipRegion &amp;= systemClip();<br />
if (clipEnabled)<br />
clipRegion &amp;= clip;<br />
<br />
simpleClip = (clipRegion.rects().size() <= 1);<br />
<br />
const QRect r = clipRegion.boundingRect();<br />
gl_setclippingwindow(r.left(), r.top(),<br />
r.x() + r.width(),<br />
r.y() + r.height());<br />
}</source> <br />
The <tt>setClip()</tt> helper function is called from our custom implementation of [[Qt:Документация 4.3.2/qpaintengine#updateState | updateState()]], and enables clipping to the given region. An empty region means that clipping is disabled.<br />
<br />
Our custom update function also makes use of the <tt>updateClip()</tt> helper function that checks if the clip is "simple", i.e., that it can be represented by only one rectangle, and updates the clip region in [http://www.svgalib.org SVGAlib].<br />
<source lang="cpp-qt"> void SvgalibPaintEngine::drawRects(const QRect *rects, int rectCount)<br />
{<br />
const bool canAccelerate = simplePen &amp;&amp; simpleBrush &amp;&amp; simpleMatrix<br />
&amp;&amp; simpleClip &amp;&amp; opaque &amp;&amp; aliased<br />
&amp;&amp; sourceOver;<br />
if (!canAccelerate) {<br />
QRasterPaintEngine::drawRects(rects, rectCount);<br />
return;<br />
}<br />
<br />
for (int i = 0; i < rectCount; ++i) {<br />
const QRect r = matrix.mapRect(rects[i]);<br />
if (brush != Qt::NoBrush) {<br />
gl_fillbox(r.left(), r.top(), r.width(), r.height(),<br />
brush.color().rgba());<br />
}<br />
if (pen != Qt::NoPen) {<br />
const int c = pen.color().rgba();<br />
gl_hline(r.left(), r.top(), r.right(), c);<br />
gl_hline(r.left(), r.bottom(), r.right(), c);<br />
gl_line(r.left(), r.top(), r.left(), r.bottom(), c);<br />
gl_line(r.right(), r.top(), r.right(), r.bottom(), c);<br />
}<br />
}<br />
}</source> <br />
Finally, we accelerated that drawing of non-rotated, aliased and opaque rectangles in our reimplementation of the [[Qt:Документация 4.3.2/qpaintengine#drawRects-2 | drawRects()]] function. The [[Qt:Документация 4.3.2/qrasterpaintengine | QRasterPaintEngine]] fallback is used whenever the rectangle is not simple enough.<br />
<div id="step-3-making-the-widgets-aware-of-the-custom-paint-engine"></div><br />
==Step 3: Making the Widgets Aware of the Custom Paint Engine==<br />
<br />
To activate the custom paint engine, we also need to implement a corresponding paint device and window surface and make some minor adjustments of the graphics driver.<br />
<br />
*[[#implementing-a-custom-paint-device | Implementing a Custom Paint Device]]<br />
*[[#implementing-a-custom-window-surface | Implementing a Custom Window Surface]]<br />
*[[#adjusting-the-graphics-driver | Adjusting the Graphics Driver]]<br />
<div id="implementing-a-custom-paint-device"></div><br />
===Implementing a Custom Paint Device===<br />
<br />
The custom paint device can be derived from the [[Qt:Документация 4.3.2/qcustomrasterpaintdevice | QCustomRasterPaintDevice]] class. Reimplement its [[Qt:Документация 4.3.2/qpaintdevice#paintEngine | paintEngine()]] and [[Qt:Документация 4.3.2/qcustomrasterpaintdevice#memory | memory()]] functions to activate the accelerated paint engine:<br />
<source lang="cpp-qt"> class SvgalibPaintDevice : public QCustomRasterPaintDevice<br />
{<br />
public:<br />
SvgalibPaintDevice(QWidget *w);<br />
~SvgalibPaintDevice();<br />
<br />
void* memory() const { return QScreen::instance()->base(); }<br />
<br />
QPaintEngine *paintEngine() const { return pengine; }<br />
int metric(PaintDeviceMetric m) const;<br />
<br />
private:<br />
SvgalibPaintEngine *pengine;<br />
};</source> <br />
The [[Qt:Документация 4.3.2/qpaintdevice#paintEngine | paintEngine()]] function should return an instance of the <tt>SvgalibPaintEngine</tt> class. The [[Qt:Документация 4.3.2/qcustomrasterpaintdevice#memory | memory()]] function should return a pointer to the buffer which should be used when drawing the widget.<br />
<br />
Our example driver is rendering directly to the screen without any buffering, i.e., our custom pain device's [[Qt:Документация 4.3.2/qcustomrasterpaintdevice#memory | memory()]] function returns a pointer to the framebuffer. For this reason, we must also reimplement the [[Qt:Документация 4.3.2/qpaintdevice#metric | metric()]] function to reflect the metrics of framebuffer.<br />
<div id="implementing-a-custom-window-surface"></div><br />
===Implementing a Custom Window Surface===<br />
<br />
The custom window surface can be derived from the QWSWindowSurface class. QWSWindowSurface manages the memory used when drawing a window.<br />
<source lang="cpp-qt"> class SvgalibSurface : public QWSWindowSurface<br />
{<br />
public:<br />
SvgalibSurface();<br />
SvgalibSurface(QWidget *w);<br />
~SvgalibSurface();<br />
<br />
void setGeometry(const QRect &amp;rect);<br />
bool isValid() const { return true; }<br />
bool scroll(const QRegion &amp;region, int dx, int dy);<br />
QString key() const { return QLatin1String("svgalib"); }<br />
<br />
bool attach(const QByteArray &amp;) { return true; }<br />
void detach() {}<br />
<br />
QImage image() const { return QImage(); }<br />
QPaintDevice *paintDevice() { return pdevice; }<br />
QPoint painterOffset() const;<br />
<br />
private:<br />
SvgalibPaintDevice *pdevice;<br />
};</source> <br />
We can implement most of the pure virtual functions inherited from QWSWindowSurface as trivial inline functions, except the [[Qt:Документация 4.3.2/qwindowsurface#scroll | scroll()]] function that actually makes use of some hardware acceleration:<br />
<source lang="cpp-qt"> bool SvgalibSurface::scroll(const QRegion &amp;region, int dx, int dy)<br />
{<br />
const QVector<QRect> rects = region.rects();<br />
for (int i = 0; i < rects.size(); ++i) {<br />
const QRect r = rects.at(i);<br />
gl_copybox(r.left(), r.top(), r.width(), r.height(),<br />
r.left() + dx, r.top() + dy);<br />
}<br />
<br />
return true;<br />
}</source> <div id="adjusting-the-graphics-driver"></div><br />
===Adjusting the Graphics Driver===<br />
<br />
Finally, we enable the graphics driver to recognize an instance of our custom window surface:<br />
<source lang="cpp-qt"> QWSWindowSurface* SvgalibScreen::createSurface(QWidget *widget) const<br />
{<br />
if (base()) {<br />
static int onScreenPaint = -1;<br />
if (onScreenPaint == -1)<br />
onScreenPaint = qgetenv("QT_ONSCREEN_PAINT").toInt();<br />
<br />
if (onScreenPaint > 0 || widget->testAttribute(Qt::WA_PaintOnScreen))<br />
return new SvgalibSurface(widget);<br />
}<br />
return QScreen::createSurface(widget);<br />
}<br />
<br />
QWSWindowSurface* SvgalibScreen::createSurface(const QString &amp;key) const<br />
{<br />
if (key == QLatin1String("svgalib"))<br />
return new SvgalibSurface;<br />
return QScreen::createSurface(key);<br />
}</source> <br />
The [[Qt:Документация 4.3.2/qscreen#createSurface | createSurface()]] functions are factory functions that determines what kind of surface a top-level window is using. In our example we only use the custom surface if the given window has the [[Qt:Документация 4.3.2/qt#WidgetAttribute-enum | Qt::WA_PaintOnScreen]] attribute or the [[Qt:Документация 4.3.2/qtopiacore-envvars#qt-onscreen-paint | QT_ONSCREEN_PAINT]] environment variable is set.<br />
<br />
<br />
{{Qt4.3.2_footer}}</div>Root