DIB engine

Gavriel State gav at transgaming.com
Fri Sep 27 20:14:36 CDT 2002


Ove Kaaven wrote:
> Well, here is the DIB engine that a couple of people at TransGaming
> (mostly David Hammerton, I think) did some work on a while ago, I finally
> got around to review it and make sure it compiles against the current
> ReWind (though perhaps it needs a few tweaks to compile against Wine).
> It's not all that complete by any means, but we wanted to get it out
> there, so feel free to comment on it (or even apply it to Wine if it's
> good enough).

Primary attribution should go to Jonathan Meunier, a co-op student who
worked with us earlier this year.  David Hammerton, Peter Hunniset, and
I all assisted with it to one degree or another.

If there is any general interest in pursuing DIB Engine work, we would
of course appreciate it if developers are willing to license their
contributions to ReWind.

Ove seems to have forgotten to include the documentation, which includes
some nice background on DIB issues in general, and should go into the
documentation directory.

  -Gav

-- 
Gavriel State, CEO
TransGaming Technologies Inc.
http://www.transgaming.com/
gav at transgaming.com
-------------- next part --------------
                          TRANSGAMING TECHNOLOGIES
                          DIB ENGINE DOCUMENTATION
                               (GDI RENDERER)


Copyright (c) 2002 TransGaming Technologies Inc.


SCENARIO
--------

The Win32 API allows for a graphics format called DIBSections. DIBSections
allow the application to write to the image in two ways: Direct Access and
through GDI.
Direct Access means that the application can simply write whatever data it
likes to the image - the application has a pointer to the physical image
bits, and can write to this with no problem. In ReWind's X11 Driver we can
emulate this kind of access by using XImages.
The GDI access allows the application to do a whole heap of extra stuff to
its graphics, including special rendering such as lines, polygons, ellipses
and so on. ReWind emulates such calls through the use of X11's renderer by
using XPixmaps.
With a DIBSection, the Win32 API allows both of these features to be used
on a single image. This is currently supported by ReWind, but it can be slow
at times and rather 'hacky'. This is achieved using the following method:
 o When a DIBSection is created, space is allocated for the application
   (where the application can directly write to). This is also an XImage.
 o Another XImage is created for 'conversions' (see depth conversion).
 o An XPixmap (which is a X Drawable) is created on the X Server.
 o The application-side data is memory protected to no access.

Now, ReWind's X11 driver keeps track of which "image" is most up-to-date,
it has 3 mods: gdimod, appmod and insync. (There is actually a 4th mod
called 'auxmod' which is used for auxiliary tasks such as OpenGL). These
mods represent different states, as follows:
 o gdimod means that the XPixmap has the most up-to-date version of the
   image, it was written to last.
 o appmod means that the application has the most up-to-date version, it
   has written the image data manually.
 o insync means that the both the images are up-to-date, they contain the
   same data.

The application can then write into the memory which it is given direct
access to, but when it tries to do so a segmentation fault is raised because
the memory has been protected. This segmentation fault is caught by ReWind
which it recognizes as an attempt to access the application data of a
DIBSection. A "coercion" is now called on this DIBSection. If the DIBSection
is in gdimod at the time of the segmentation fault, a copy is necessary
before we allow the application to write to the DIBSection. The Pixmap is
then fetched from X and placed into the XImage in the correct format.
The Application is now free to write to the image data, the DIBSection
is placed in appmod.
A similar thing happens when a GDI painting function gets called, we ensure
that the DIBSection is in gdimod (The Pixmap is up-to-date). X is then free
to to its rendering.

A Problem: Depth conversions and X Limitations:

There are many other "nicer" ways that could, in theory, work. With some
extensions X is able to render into a XImage, we could use Shared Memory
Pixmaps or we could work on getting the upcoming on-the-fly X depth
changing into XFree86 4.3. Unfortunately none of these are complete enough
to work for our needs. One of the big things that many of them lack is
palette support (8bit graphics).

So, presently XPixmaps must be in the depth format that the users current
X is running at. But the application only knows one way to draw to the
DIBSection: The format it requested. This means we have to do depth
conversions when we do our coercions from one format to another. This can
be slow, particularly if we are constantly doing the conversions. One of
the worst cases is when the application requested 8 bit paletted mode
and X is running in 24bit mode. A copy from appmod to gdimod/insync
involves indexing each color and placing it in the new XImage, then sending
it over to X. A copy in the other direction involves a reverse palette
lookup, for each pixel we have to cycle through the 256 possible colors
and find the correct index for them. This gets quite harsh on X when doing
a large image, for example take a 1024x768 screen at 24bits (padded to
32bits): That becomes a 3 megabyte copy every time, doing that often
can really slow things down.

DIRECT DRAW USAGE
-----------------

One important use of DIBSections is DirectDraw. Although games may not
explicitly use DIBSections themselves, ReWind does. In Rewind a DirectDraw
surface is basically a DIBSection. This is because DirectDraw can be used
much like a DIBSection: The application can draw directly to it, yet Win32
can still do GDI rendering to it. For this reason many Win32 DirectDraw
applications suffer serious performance problems as a result of
DIBSections. Several games you may wish to look at are StarCraft (not
too bad because it uses a 640x480 surface) and Age of Empires 2 (badly
effected, as it uses a 1024x768 paleted surface).

A BETTER SOLUTIONS: THE DIBENGINE
---------------------------------

A better solution for this problem has constantly been discussed and is
the DIB Engine. The purpose of the DIB Engine is to implement a fully
functional GDI renderer capable of doing all the things X is presently
used for, plus others which are currently unimplemented in any way.
The DIB Engine would basically be able to take care of all GDI rendering
when needed itself by rendering into the application memory (at the depth
requested by the application). This would save on the copying backwards
and forwards most of the time. (Although we would still have the copy
to X when blitting to the primary surface).
A DIBEngine has to implement a lot of functionality and must include the
raw functions to render things like lines, polygons, ellipses and so on
to the image.
Another functionality of a DIBEngine should be to understand the ROP
modes given to the various blitting functions. ROP stands for Raster
Operations and is a method by which an application can make customize a
blit fairly extensively. In Win32 there are two types of ROP's: Binary
ROP's and Tenerary ROP's. Tenerary ROP's allow for up to 256 different
types of blitting and are described by a string in reverse polish
notation. An example Tenerary ROP could be DPSoo which is described as
"Destination OR'd with Brush (pattern) OR'd with Source" and then
blitted into the source. That is a fairly simple ROP3 code.
Currently there is no suitable external library which could be exploited
to make a DIBEngine in ReWind. One of the more promising libraries,
Microwindows, has problems with different depths and ultimately has to be
hooked into the underlying driver and hence does not solve the problem
of removing the coercions.

TRANSGAMING'S DIBENGINE
-----------------------

TransGaming Technologies has been developing a DIBEngine in order to
finally solve all the problems discussed above.
The DIBEngine developed by TransGaming is partially complete, but more
work is still needed for it to be fully functional. Current features
include:
 o Drawing of lines
 o Partial drawing of ellipses
 o Drawing of polygons (several of the implementations, such as Polygon,
   Polyline, etc)
 o Filling of polygons (including patterns)
 o Pattern blitting
 o ROP2 and ROP3 engines
Most of the support is there to complete the DIBEngine, for example the
incomplete primitives can make use of the pattern blitting and so on.

There is still a some functionality that has to be completed, and the
current TODO list is as follows:
 o Implement outlined and filled shapes.
 o Implement curved shapes (Ellipse, Chord, Pie, Arc, etc).
 o Complete other drawing functionality (Round Rect, SetPixal etc).
 o Implement the different pens (Varying thickness, dotted, geometric,
   etc).
 o Line drawing needs to implement draw_last_point flag.
 o Brushes can only be 8x8 in Windows 95, we need to care about this.
 o Implement of clipping regions (Win32 has many types of clipping
   including rectangles, elliptic and more).
 o Implement text/fonts.
 o Take care of SetBrushOrgEx
Currently the DIBEngine only supports a 16bit X Server and 16 bit drawing
this means we need to:
 o Implement drawing for all possible depths (modify underlying pixel draw
   functions only).
 o Support Paletted modes.
 o Currently X11DRV_CreateBitmap only supports the current X depth. If a
   DIBSection is created at 32bits, and thus we try to use a 32bit brush,
   the whole thing will break. We either need to do depth conversions
   before calling X11DRV_CreateBitmap or do something else.
Some things which need fixing up include:
 o Find depth masks for HBITMAPs
 o Properly implement BitBlt/PatBlt's and StertchBlt's. BitBlt takes the
   destination's DC functions, but this may not be safe if the source is
   not a DIBSection (see the information below on hooking into ReWind).
 o Optimzation. Currently the DIBEngine is not as fast as X for most
   drawing functions. Speedups can be done in the area of the ROP parser,
   pixel drawing, line drawing and filling. The code contains some
   comments of specific areas that need work.
 o DLL Seperation: Ideally the DIBEngine should be placed into its own
   DLL. This will allow it to be used for different graphics drivers,
   amongst other things.

HOOKING INTO REWIND
-------------------

For each GDI function that exists there is a driver-specific wrapper
function that does some simply checking / optimizing / calculations
before sending it onto the drivers specific rendering functions. For the
X11DRV these exist in graphics/x11drv/graphics.c. This is where we divert
calls to the DIBEngine when necessary.
For speed optimizations (minimizing the number of coercions that take
place) we put several conditions on which renderer to use. If the DIBSection
is in gdimod (eg, Pixmap is most up-to-date) we use the drivers (eg, x11's)
renderer; if the DIBSection is in appmod we use the DIBEngine.

It should be noted that by doing this, the term 'gdimod' is now redundant
because infact a DIBSection could be in appmod yet have been last modified
by a GDI function.



More information about the wine-devel mailing list