Outline of DirectDraw Architecture
This is an outline of the architecture. Many details are
skipped, but hopefully this is useful.
DirectDraw inheritance tree
Most of the DirectDraw functionality is implemented in a common base
class. Derived classes are responsible for providing display
mode methods (EnumDisplayModes,
and internal functions called to create primary and backbuffer
User provides for DirectDraw capabilities based on drawing to a
Wine window. It uses the User DirectDrawSurface
implementation for primary and backbuffer surfaces.
XVidMode attempt to use the XFree86 VidMode extension to set the
display resolution to match the parameters to SetDisplayMode.
DGA2 attempt to use the XFree86 DGA 2.x extension to set the
display resolution and direct access to the framebuffer, if the
full-screen-exclusive cooperative level is used. If not, it just
uses the User implementation.
DirectDrawSurface inheritance tree
DIB Fake Z-Buffer
| | |
User DGA2 DIBTexture
Main provides a very simple base class that does not implement
any of the image-related functions. Therefore it does not place any
constraints on how the surface data is stored.
DIB stores the surface data in a DIB section. It is used by the
Main DirectDraw driver to create off-screen surfaces.
User implements primary and backbuffer surfaces for the User
DirectDraw driver. If it is a primary surface, it will attempt to keep itself
synchronized to the window.
DGA2 surfaces claims an appropriate section of framebuffer space
and lets DIB build its DIB section on top of it.
Fake Z-Buffer surfaces are used by Direct3D to indicate that a
primary surface has an associated z-buffer. For a first implementation, it
doesn't need to store any image data since it is just a placeholder.
(Actually 3D programs will rarely use Lock or
GetDC on primary
surfaces, backbuffers or z-buffers so we may want to arrange for
lazy allocation of the DIB sections.)
Only the most recent version of an interface needs to be implemented.
Other versions are handled by having thunks convert their parameters
and call the root version.
Not all interface versions have thunks. Some versions could be combined
because their parameters were compatible. For example if a structure
changes but the structure has a dwSize field, methods using that
structure are compatible, as long as the implementation remembers to take the
dwSize into account.
Interface thunks for Direct3D are more complicated since the paradigm
changed between versions.
Logical Object Layout
The objects are split into the generic part (essentially the fields for
Main) and a private part. This is necessary because some objects
can be created with CoCreateInstance, then initialized later. Only
at initialization time do we know which class to use. Each class
except Main declares a Part structure and
adds that to its Impl.
For example, the DIBTexture DirectDrawSurface
implementation looks like this:
union DIBTexture_data data; /*declared in the real header*/
struct DIB_DirectDrawSurfaceImpl_Part dib;
struct DIBTexture_DirectDrawSurfaceImpl_Part dibtexture;
So the DIBTexture surface class is derived from the
DIB surface class and it adds one piece of data, a union.
Main does not have a Part structure. Its
fields are stored in
To access private data, one says
DIBTexture_DirectDrawSurfaceImpl* priv = This->private;
Classes have two methods relevant to object creation, Create
and Construct. To create a new object, the
Create method of the class is called. It allocates enough memory
for IDirectDrawImpl or IDirectDrawSurfaceImpl
as well as the private data for derived classes and then calls
Each class Construct method calls the base class
Construct, then does the necessary initialization.
For example, creating a primary surface with the user ddraw driver
calls User_DirectDrawSurface_Create which allocates memory for the
object and calls User_DirectDrawSurface_Construct to initialize it.
This calls DIB_DirectDrawSurface_Construct which calls