Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

476 lines
22 KiB

"Ramp is hell," says Gen. William Tecumseh Sherman, now 60, in an address to
a Columbus, Ohio, reunion of the G.A.R. (Grand Army of the Republic). "There is
many a boy here who looks on ramp as all speed, but, boys, it is all hell. You
can bear this warning voice to generations yet to come."
(Quote from 1880 in reference to the U.S. Civil Ramp)
Introduction
============
First, some philosophy and intent. Ramp is provided in DX6 for compatibility
with DX5, and our implementation is intended to work as well but no better than
ramp did in DX5. We make no attempt to clean up or generalize ramp, and we
hope to maintain the same quirks the original implementation had, largely
through the literal reuse of DX5 code, where possible.
That said, it is useful to know where the ramp files in DX6 came from in DX5 so
the code can be examined in its original context when questions arise. The
diesel\direct3d\rast\rampmat (Ramp Material) directory handles creating
rampmap's and palettes from materials and textures. The
diesel\direct3d\rast\rampspan directory has the span rasterizers for ramp.
DX6 DX5
diesel\direct3d\rast\rampmat\ diesel\direct3d\drivers\
cmap.h . . . . . . . . . . . . include\cmap.h
colall.h . . . . . . . . . . . include\colall.h
indcmap.cpp . . . . . . . . . . gen\indcmap.c
indcmap.h . . . . . . . . . . . include\indcmap.h
palette.cpp . . . . . . . . . . gen\palette.c
palette.h . . . . . . . . . . . include\palette.h
pch.cpp . . . . . . . . . . . . new, for faster compiles
rampif.h . . . . . . . . . . . new, interface to d3dif
rampmap.cpp . . . . . . . . . . gen\rampmap.c
rampmap.h . . . . . . . . . . . include\rampmap.h
rampmat.cpp . . . . . . . . . . ramp\ramplt.cpp
rampmat.hpp . . . . . . . . . . ramp\ramplti.h
rampmisc.h . . . . . . . . . . new, odds and ends
rgbmap.cpp . . . . . . . . . . gen\rgbmap.c
rgbmap.h . . . . . . . . . . . include\rgbmap.h
diesel\direct3d\rast\rampspan\ diesel\direct3d\drivers\
rrampgen.cpp . . . . . . . . . ramp\rampgen.c
Other files in rampspan directory based on general beaded span code.
Ramp rasterization is pretty straight forward. We just do what the DX5 code
did, within the new span rasterization architecture. Therefore, the rest of
this document will describe the ramp material code.
Exported API's to d3dif
=======================
These are all declared in rampif.h and implemented in rampmat.cpp. For
convenience, the in file documentation is gathered together here.
//-----------------------------------------------------------------------------
//
// RLDDIRampCreate
//
// Creates the original RLDDIRampLightingDriver with associated lists. The
// pointer returned is kept in pCtx->pRampDrv.
//
//-----------------------------------------------------------------------------
RLDDIRampLightingDriver* RLDDIRampCreate(PD3DI_RASTCTX pCtx);
//-----------------------------------------------------------------------------
//
// RLDDIRampDestroy
//
// Destroys a RLDDIRampLightingDriver with all associated objects and memory.
// The pCtx->pRampDrv pointer should be set to NULL after this occurs.
//
//-----------------------------------------------------------------------------
void RLDDIRampDestroy(RLDDIRampLightingDriver* drv);
//-----------------------------------------------------------------------------
//
// RLDDIRampBeginSceneHook
//
// Called at clear time to advance material ages and process deferred color
// setting. Also deletes orphaned IntMaterials.
//
//-----------------------------------------------------------------------------
void RLDDIRampBeginSceneHook(RLDDIRampLightingDriver* driver);
//-----------------------------------------------------------------------------
//
// RLDDIRampEndSceneHook
//
// Called at update time to reclaim unused color resources and reclaim
// memory for old IntMaterials.
//
// The age1 list will contain materials which were active last frame
// and have not been used since the last Clear.
// We remove their colour resources.
//
// The agemax list will contain inactive materials which have not
// been used for AGE_MAX-1 frames. These are obsolete and we reclaim
// their memory.
//
// NOT CALLING THIS CONSTITUTES A MEMORY LEAK.
//
//-----------------------------------------------------------------------------
void RLDDIRampEndSceneHook(RLDDIRampLightingDriver* driver);
//-----------------------------------------------------------------------------
//
// RLDDIRampMaterialChanged
//
// Called when the contents of D3DMATERIAL we have already made a ExtMaterial
// for changes.
//
//-----------------------------------------------------------------------------
long RLDDIRampMaterialChanged(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat);
//-----------------------------------------------------------------------------
//
// RLDDIRampSetMaterial
//
// Called when a D3DLIGHTSTATE_MATERIAL changes, which sets the
// driver->current_material.
//
//-----------------------------------------------------------------------------
long RLDDIRampSetMaterial(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat);
//-----------------------------------------------------------------------------
//
// RLDDIRampCreateMaterial
//
// Called to create a new ExtMaterial for a given D3DFE_MATERIAL.
//
//-----------------------------------------------------------------------------
long RLDDIRampCreateMaterial(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat, PD3DI_RASTCTX pCtx);
//-----------------------------------------------------------------------------
//
// RLDDIRampDestroyMaterial
//
// Called to delete a ExtMaterial and all associated underlying memory and rampmap
// allocations for a given D3DFE_MATERIAL.
//
//-----------------------------------------------------------------------------
long RLDDIRampDestroyMaterial(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat);
//-----------------------------------------------------------------------------
//
// RLDDIRampMaterialToPixel
//
// Call to convert a previously created material to a color for use in clearing
// the color buffer, for example.
//
//-----------------------------------------------------------------------------
unsigned long RLDDIRampMaterialToPixel(RLDDIRampLightingDriver* driver,
D3DMATERIALHANDLE hMat);
//-----------------------------------------------------------------------------
//
// RLDDIRampUpdateDDPalette
//
// Called before the destination DirectDraw surface is displayed, to set its palette.
//
//-----------------------------------------------------------------------------
long RLDDIRampUpdateDDPalette(PD3DI_RASTCTX pCtx)
/*
* Find what range of values lighting should take. The base is the
* pixel value (in fixed point) of the dark end of the material. The
* shift value is user to convert a 0.16 fixed point shade into the
* range needed for the material. e.g.
*
* pixel = base + (VALTOFX8(shade) << shift);
*
*/
HRESULT ExtMaterial::FindLightingRange(unsigned long* base,
unsigned long* size,
BOOL* specular,
unsigned long** texture_colors);
//-----------------------------------------------------------------------------
//
// RLDDIRampMakePaletteRGB8
//
// Call to set up the RGB8 palette and rampmap. This is a palette of 216 (== 6**3)
// entries of 6 gradations each for r, g, b. Using this palette requires
// multiplies by 6.
//
//-----------------------------------------------------------------------------
long RLDDIRampMakePaletteRGB8(RLDDIRampLightingDriver* driver);
Classes
=======
There are 3 primary classes that handle ramp materials. All the classes make
significant use of the diesel\direct3d\d3dim\inc\lists.hpp linked list handling
macros. See lists.hpp (especially the example code at the end) for details.
ExtMaterial (rampmat.hpp).
/*
* An ExtMaterial is the underlying driver object for an LPDIRECT3DMATERIAL.
* When used, it creates IntMaterials which are distinguished by different
* ambient light, fog, D3DMATERIAL value etc.
*
* The ExtMaterials are kept on a list in the driver and if not explicitly
* freed, they are cleaned up when the driver is destroyed.
*
* The IntMaterials can outlive the ExtMaterial in the case that the
* ExtMaterial is destroyed right after use. We add these orphans to a list
* which is emptied at Clear time since after Clear, no pixels are visible
* which were rendered with the IntMaterial and it can be freed.
*/
IntMaterial (rampmat.hpp).
/*
* The IntMaterial is derived from an ExtMaterial taking into account the
* driver state when the ExtMaterial was used. Normally IntMaterials are
* on a list in their owning ExtMaterial. If the external material is
* destroyed, any active internal materials which it owned are
* transferred to an orphans list in the driver. This is cleared out
* next time Clear is called.
*
* The internal material has a list of underlying RampMaterials. For
* a non-textured material, there is exactly one and for a textured
* material, there is one per color in the texture's palette. The
* ramp materials track color sharing between internal materials and
* handle the details of allocating color resources.
*
* Internal materials are also chained onto one of a number of lists
* based on their age. The age of a material is the number of frames
* since it was last used to render something. When a material is
* aged, it is rejuvenated by moving it to the age=0 list. Each
* frame, the lists are rotated by one notch and materials on the
* oldest list are reclaimed.
*
* A material is either active or inactive. Active materials have
* color resources and are either on the age=0 list (active this
* frame) or the age=1 list (active last frame). When an inactive
* material is used, it allocates color resources by attempting to
* activate the underlying ramp materials.
*
* At the end of the frame, on Update, any active materials on the
* age=1 list must be materials which were active last frame but were
* not used this frame. We remove their color resources by
* deactivating the underlying ramp materials.
*/
RampMaterial (rampmat.hpp).
/*
* RampMaterials are used by internal materials to represent ranges of
* colors. They perform low level color allocation by allocating
* color ranges (RLDDIRamps) from a rampmap.
*
* A textured internal material can use many ramp materials.
* Several internal materials can use the same ramp material if the
* colors match. This can happen easily if many textures use the same
* palette. The ramp material maintains a usage of how many internal
* materials are using it and is freed when the last one stops.
*
* Ramp materials, like internal materials are either active or
* inactive. Active materials have color resources and inactive
* materials do not. A ramp material is made active when any of its
* internal material users are active and inactive when none of then
* are active. To track this a count of how many active users is
* maintained.
*
* When a material is made active, it attempts to allocate a color
* range to use. If that is successful, it sets the colors in the
* range to an appropriate ramp of colors. If is no more space in the
* colormap for a new range, it finds the closes active ramp material
* and shares its ramp.
*
* To track active materials and sharing materials, the driver has a
* list of active materials and each material has a list of sharers.
* The sharers list is only valid for materials which are both active
* and which own their ramp.
*/
RLDDIColormap (cmap.h). Common name cmap. Holds pointer to a
RLDDIColorAllocator, and cmap->priv->map is the master 32K pixelmap.
RLDDIRamp (rampmap.h). Common name ramp. Is an element of a RLDDIRampmap
circular queue, and consists of a base (int), size (int), and free (int, BOOL
in meaning) elements. It is used to allocate space in the master pixelmap.
RLDDIRampmap (rampmap.h). Common name rampmap. Holds circular queues of
RLDDIRamp objects on free and allocated lists. It also holds a pointer back to
the cmap object.
RLDDIPalette (palette.h). Common name pal. Holds palette entries, a list of
free palette entries, and methods to allocate, set, and free colors.
A Day in the Life of a Ramp
===========================
At the beginning of time, RLDDIRampCreate (rampmat.cpp) is called. This
creates and initializes a RLDDIRampLightingDriver with its embedded
RLDDISoftLightingDriver. The structure is zeroed, then the lists and hash
table is initialized. Then InitRampmap is called. If the output surface is
PALETTE4 or PALETTE8, RLDDICreatePalette (palette.cpp) is used to create a 16
or 256 palette in driver->palette. Otherwise, RLDDICreateRGBMap (rgbmap.cpp)
is called to create driver->rgbmap. An rgbmap is just the masks and shifts
necessary to turn an arbitrary 24 bit RGB color into its nearest equivalent in
the output surface format. Thus, rgbmap->alloc.allocate_color doesn't actually
allocate anything, it just returns the nearest output color to the input 24 bit
RGB color.
Once an RLDDIColorAllocator (refered to by alloc) is obtained, a
RLDDICreateIndirectColormap of static size 32K (the max possible, since color
indices in DX5 and DX6 code are 1.15.16) is created. A RLDDIColormap called
cmap is created, and alloc is used to fill the entire 32K entries with black.
Then, RLDDIIndirectColormapGetMap is used to access the actual color map we
malloc'ed and filled with black (cmap->priv->map), and a pointer to this master
32K array of DWORDS is pointed to by driver->pixelmap and pCtx->pRampMap.
Thus, pCtx->pRampMap is used to do the final color dereference in the ramp
rasterizers.
Then, RLDDICreateRampmap (rampmap.cpp) is use to create a RLDDIRampmap
(called rampmap) and its initial RLDDIRamp (called ramp).
Then, we are finally finished with RLDDIRampCreate.
Next, we would expect to see 1 or more RLDDIRampCreateMaterial's. I take this
opportunity to fill driver->fog_enable, fog_color with the current renderstate
values. D3DIF keeps these, along with driver->driver.ambient (represents
D3DLIGHTSTATE_AMBIENT) up to date. Then, we create a new ExtMaterial (extmat),
and add this material to the drivers->materials list. This list is currently
used for cleanup and material handle lookup. We intend to get rid of the
material handle lookup by forming an association in the runtime. We end by
initializing the ExtMaterial's copy of the D3DMATERIAL for this material with
extmat->SetMaterial.
The next thing that should happen is RLDDIRampSetMaterial should be called.
This is not what happens when a material changes, for that,
RLDDIRampMaterialChanged is called. RLDDIRampSetMaterial sets the
driver->current_material for later activation, and is called when the
D3DLIGHTSTATE_MATERIAL is set.
Note that nothing much has really happened yet. Next, setup (the rampspan
rasterizer, right now) innocently calls a RAMP_SERVICE_FIND_LIGHTINGRANGE
service to find what its ramp base, size, and texture ramp are. This calls
driver->current_material->FindLightingRange, and causes the ramp to actually be
created. First, ExtMaterial::FindIntMaterial is called to find the internal
material that matches the external material's current characteristics. If
there is no matching IntMaterial (initially there are no internal materials),
one is created. Next we create an array of RampMaterial's.
If we are texture mapping, we create 1 RampMaterial* for every color in the
texture palette. We also create an array of longs called "colors" that is the
same size as the texture palette, and will end up being pointed to by
pTex->pRampmap where it will be used as the final dereference in the ramp
rasterizer texture read functions. Then, for each color in the texture
palette, a temporary material is created in which the current material's
ambient and diffuse factors are modulated by the texture palette color. Note
that this implies that the one and only supported texture function for ramp is
modulate, unless the user asks for D3DTBLEND_COPY (I assume we will support
this with another bead, at some point). Then RampMaterial::Find is called to
find or create a matching RampMaterial*. Here is where a hash comes in.
RampMaterial's are hashed based on material diffuse color for fast lookup. If
a perfectly matching RampMaterial is found, it is used, otherwise, a new
RampMaterial with the given D3DMATERIAL is created. At this point the array of
RampMaterial's is just acting like an array of D3DMATERIAL's with hash values.
Now we are done with the construction of IntMaterial, and IntMaterial has all
the RampMaterial's it needs to create all the pixelmaps, rampmaps, etc. we will
need to actually draw a picture.
The non-texture mapped case is the same as above, except only one RampMaterial
is created (for the current one and only D3DMATERIAL associated with this
RampMaterial).
Next, in ExtMaterial::FindLightingRange, after an IntMaterial has been found or
created, IntMaterial::FindLightingRange is called. The first thing IntMaterial
does is see if it is active. If it is, Active() need only update the age lists
so it stays active. Otherwise, as will happen the first time through, we must
activate the material.
Now RampMaterial::Activate is called for each individual RampMaterial. This
calls RampMaterial::AllocateColors. This calls RLDDIRampmapAllocate with the
driver->rampmap to allocate some space in the global pixelmap with a new or
used (but free) RLDDIRamp. Remember, RLDDIRamp's in RLDDIRampmap's are just
for bookkeeping, they don't really store anything. Then we call
RampMaterial::SetColors which calls RampMaterial::SetColorsFog or
RampMaterial::SetColorsStd. This finally calls cmap->set_color which sets the
appropriate entry in the global pixelmap (that we allocated with the
RLDDIRampmap) with the alloc function discussed above. For non-palletized
output surfaces, this just makes an output color given 24 bits of r, g, and b
and the surface's color masks. For palletized output surfaces, this calls
RLDDIPaletteAllocateColor in palette.c, which uses the following basic
algorithm.
If an exact match to the desired color already exists in the surfaces palette,
cool, return it. Otherwise, if there are unused palette entries in the
surface, make one that matches perfectly. Otherwise, find the closest matching
color in the palette (uses dr*dr + dg*dg + db*db where dr = r - palette->r as a
metric) and return that.
It is probably worth mentioning here that only a shadow copy of the surfaces
palette, driver->ddpalette is updated by the palette.cpp SetColor function.
The palette gets updated in the direct draw output surface by
RLDDIUpdateDDPalette.
To delete a material, RLDDIRampDestroyMaterial is called. First, the
ExtMaterial destructor is called. If an IntMaterial associated with the
ExtMaterial is still active, the IntMaterial is placed on the driver->orphans
list. Orphans are cleaned up when RLDDIRampBeginSceneHook is called, or when
RLDDIRampDestroy is called to destroy the whole RLDDIRampLightingDriver.
Stuff We Do Different (from DX5)
================================
The initialization code in InitRampmap (rampmat.cpp) is all of private
interpretation, mostly from the DX5 source drivers\win32\ddraw.c. This code
could not be literally stolen, since it brings in a whole bunch of undesirable
RLDDI stuff.
RLDDIUpdateDDPalette (palette.cpp) is likewise from DX5 source
drivers\win32\ddraw.c. I'm not sure where this was ever called in DX5, but I
have put it sucessfully (so far) in rampif.cpp after all FindLightingRange's
(which is the only thing that can change the palette to change).
Issues
======
RLDDIRampEndSceneHook is not being called. This constitutes a memory leak.
Need to move the association of the ExtMaterial's with hMat's to the runtime.
Hacked DrawPrim ramp lighting is not the same as RenderPrim (halexe.cpp).
Probably don't need to fix this if Iouri does lighting.
Apps that interpolate across vertices from different materials, like oct1 and
twist may not look exactly the same as they did on DX5, since the appearance
will depend on where the material got put in the global pixelmap. This, in
turn, depends on the exact timing of the RLDDIRampBeginSceneHook,
RLDDIRampEndSceneHook calls, which we will not reasonably be able to reproduce.
Apps Compat
===========
NT below means NT 5. 98 means memphis.
Direct3D\TestApps\D3DIm
flipcube.exe O.K. on NT/98
oct1.exe O.K. on NT/98
oct2.exe O.K. on NT/98
sphere.exe O.K. on NT/98
triangle.exe O.K. on NT/98
tunnel.exe O.K. on NT/98 Hit F9 3 times to see glitchy problem
with grid texture. Problem only exists in ramp.
twist.exe O.K. on NT/98
Direct3D\TestApps\D3DRm
egg.exe O.K. on NT/98
faces.exe O.K. on NT/98
fly.exe O.K. on NT/98
globe.exe O.K. on NT/98
globe2.exe O.K. on NT/98
hier1.exe O.K. on NT/98
hier2.exe O.K. on NT/98
quat.exe O.K. on NT/98
shadow.exe O.K. on NT/98
tex1.exe O.K. on NT/98
tex3.exe O.K. on NT/98
tex4.exe O.K. on NT/98
tex5.exe O.K. on NT/98
trans.exe O.K. on NT/98
uvis.exe O.K. on NT/98
viewer.exe O.K. on NT/98
Other
wipeout2.exe O.K. on NT/98
hyperblade (win95 only) always uses its own rendering or hardware
wargods (win95 only) always works, seems to not be using
rasterizers.
agile warrior (win95 only) O.K.
terracide (win95 only) Shows perspectivish problem that can get
quite pronounced at times.