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@transgaming.com
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.