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

  1. "Ramp is hell," says Gen. William Tecumseh Sherman, now 60, in an address to
  2. a Columbus, Ohio, reunion of the G.A.R. (Grand Army of the Republic). "There is
  3. many a boy here who looks on ramp as all speed, but, boys, it is all hell. You
  4. can bear this warning voice to generations yet to come."
  5. (Quote from 1880 in reference to the U.S. Civil Ramp)
  6. Introduction
  7. ============
  8. First, some philosophy and intent. Ramp is provided in DX6 for compatibility
  9. with DX5, and our implementation is intended to work as well but no better than
  10. ramp did in DX5. We make no attempt to clean up or generalize ramp, and we
  11. hope to maintain the same quirks the original implementation had, largely
  12. through the literal reuse of DX5 code, where possible.
  13. That said, it is useful to know where the ramp files in DX6 came from in DX5 so
  14. the code can be examined in its original context when questions arise. The
  15. diesel\direct3d\rast\rampmat (Ramp Material) directory handles creating
  16. rampmap's and palettes from materials and textures. The
  17. diesel\direct3d\rast\rampspan directory has the span rasterizers for ramp.
  18. DX6 DX5
  19. diesel\direct3d\rast\rampmat\ diesel\direct3d\drivers\
  20. cmap.h . . . . . . . . . . . . include\cmap.h
  21. colall.h . . . . . . . . . . . include\colall.h
  22. indcmap.cpp . . . . . . . . . . gen\indcmap.c
  23. indcmap.h . . . . . . . . . . . include\indcmap.h
  24. palette.cpp . . . . . . . . . . gen\palette.c
  25. palette.h . . . . . . . . . . . include\palette.h
  26. pch.cpp . . . . . . . . . . . . new, for faster compiles
  27. rampif.h . . . . . . . . . . . new, interface to d3dif
  28. rampmap.cpp . . . . . . . . . . gen\rampmap.c
  29. rampmap.h . . . . . . . . . . . include\rampmap.h
  30. rampmat.cpp . . . . . . . . . . ramp\ramplt.cpp
  31. rampmat.hpp . . . . . . . . . . ramp\ramplti.h
  32. rampmisc.h . . . . . . . . . . new, odds and ends
  33. rgbmap.cpp . . . . . . . . . . gen\rgbmap.c
  34. rgbmap.h . . . . . . . . . . . include\rgbmap.h
  35. diesel\direct3d\rast\rampspan\ diesel\direct3d\drivers\
  36. rrampgen.cpp . . . . . . . . . ramp\rampgen.c
  37. Other files in rampspan directory based on general beaded span code.
  38. Ramp rasterization is pretty straight forward. We just do what the DX5 code
  39. did, within the new span rasterization architecture. Therefore, the rest of
  40. this document will describe the ramp material code.
  41. Exported API's to d3dif
  42. =======================
  43. These are all declared in rampif.h and implemented in rampmat.cpp. For
  44. convenience, the in file documentation is gathered together here.
  45. //-----------------------------------------------------------------------------
  46. //
  47. // RLDDIRampCreate
  48. //
  49. // Creates the original RLDDIRampLightingDriver with associated lists. The
  50. // pointer returned is kept in pCtx->pRampDrv.
  51. //
  52. //-----------------------------------------------------------------------------
  53. RLDDIRampLightingDriver* RLDDIRampCreate(PD3DI_RASTCTX pCtx);
  54. //-----------------------------------------------------------------------------
  55. //
  56. // RLDDIRampDestroy
  57. //
  58. // Destroys a RLDDIRampLightingDriver with all associated objects and memory.
  59. // The pCtx->pRampDrv pointer should be set to NULL after this occurs.
  60. //
  61. //-----------------------------------------------------------------------------
  62. void RLDDIRampDestroy(RLDDIRampLightingDriver* drv);
  63. //-----------------------------------------------------------------------------
  64. //
  65. // RLDDIRampBeginSceneHook
  66. //
  67. // Called at clear time to advance material ages and process deferred color
  68. // setting. Also deletes orphaned IntMaterials.
  69. //
  70. //-----------------------------------------------------------------------------
  71. void RLDDIRampBeginSceneHook(RLDDIRampLightingDriver* driver);
  72. //-----------------------------------------------------------------------------
  73. //
  74. // RLDDIRampEndSceneHook
  75. //
  76. // Called at update time to reclaim unused color resources and reclaim
  77. // memory for old IntMaterials.
  78. //
  79. // The age1 list will contain materials which were active last frame
  80. // and have not been used since the last Clear.
  81. // We remove their colour resources.
  82. //
  83. // The agemax list will contain inactive materials which have not
  84. // been used for AGE_MAX-1 frames. These are obsolete and we reclaim
  85. // their memory.
  86. //
  87. // NOT CALLING THIS CONSTITUTES A MEMORY LEAK.
  88. //
  89. //-----------------------------------------------------------------------------
  90. void RLDDIRampEndSceneHook(RLDDIRampLightingDriver* driver);
  91. //-----------------------------------------------------------------------------
  92. //
  93. // RLDDIRampMaterialChanged
  94. //
  95. // Called when the contents of D3DMATERIAL we have already made a ExtMaterial
  96. // for changes.
  97. //
  98. //-----------------------------------------------------------------------------
  99. long RLDDIRampMaterialChanged(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat);
  100. //-----------------------------------------------------------------------------
  101. //
  102. // RLDDIRampSetMaterial
  103. //
  104. // Called when a D3DLIGHTSTATE_MATERIAL changes, which sets the
  105. // driver->current_material.
  106. //
  107. //-----------------------------------------------------------------------------
  108. long RLDDIRampSetMaterial(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat);
  109. //-----------------------------------------------------------------------------
  110. //
  111. // RLDDIRampCreateMaterial
  112. //
  113. // Called to create a new ExtMaterial for a given D3DFE_MATERIAL.
  114. //
  115. //-----------------------------------------------------------------------------
  116. long RLDDIRampCreateMaterial(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat, PD3DI_RASTCTX pCtx);
  117. //-----------------------------------------------------------------------------
  118. //
  119. // RLDDIRampDestroyMaterial
  120. //
  121. // Called to delete a ExtMaterial and all associated underlying memory and rampmap
  122. // allocations for a given D3DFE_MATERIAL.
  123. //
  124. //-----------------------------------------------------------------------------
  125. long RLDDIRampDestroyMaterial(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat);
  126. //-----------------------------------------------------------------------------
  127. //
  128. // RLDDIRampMaterialToPixel
  129. //
  130. // Call to convert a previously created material to a color for use in clearing
  131. // the color buffer, for example.
  132. //
  133. //-----------------------------------------------------------------------------
  134. unsigned long RLDDIRampMaterialToPixel(RLDDIRampLightingDriver* driver,
  135. D3DMATERIALHANDLE hMat);
  136. //-----------------------------------------------------------------------------
  137. //
  138. // RLDDIRampUpdateDDPalette
  139. //
  140. // Called before the destination DirectDraw surface is displayed, to set its palette.
  141. //
  142. //-----------------------------------------------------------------------------
  143. long RLDDIRampUpdateDDPalette(PD3DI_RASTCTX pCtx)
  144. /*
  145. * Find what range of values lighting should take. The base is the
  146. * pixel value (in fixed point) of the dark end of the material. The
  147. * shift value is user to convert a 0.16 fixed point shade into the
  148. * range needed for the material. e.g.
  149. *
  150. * pixel = base + (VALTOFX8(shade) << shift);
  151. *
  152. */
  153. HRESULT ExtMaterial::FindLightingRange(unsigned long* base,
  154. unsigned long* size,
  155. BOOL* specular,
  156. unsigned long** texture_colors);
  157. //-----------------------------------------------------------------------------
  158. //
  159. // RLDDIRampMakePaletteRGB8
  160. //
  161. // Call to set up the RGB8 palette and rampmap. This is a palette of 216 (== 6**3)
  162. // entries of 6 gradations each for r, g, b. Using this palette requires
  163. // multiplies by 6.
  164. //
  165. //-----------------------------------------------------------------------------
  166. long RLDDIRampMakePaletteRGB8(RLDDIRampLightingDriver* driver);
  167. Classes
  168. =======
  169. There are 3 primary classes that handle ramp materials. All the classes make
  170. significant use of the diesel\direct3d\d3dim\inc\lists.hpp linked list handling
  171. macros. See lists.hpp (especially the example code at the end) for details.
  172. ExtMaterial (rampmat.hpp).
  173. /*
  174. * An ExtMaterial is the underlying driver object for an LPDIRECT3DMATERIAL.
  175. * When used, it creates IntMaterials which are distinguished by different
  176. * ambient light, fog, D3DMATERIAL value etc.
  177. *
  178. * The ExtMaterials are kept on a list in the driver and if not explicitly
  179. * freed, they are cleaned up when the driver is destroyed.
  180. *
  181. * The IntMaterials can outlive the ExtMaterial in the case that the
  182. * ExtMaterial is destroyed right after use. We add these orphans to a list
  183. * which is emptied at Clear time since after Clear, no pixels are visible
  184. * which were rendered with the IntMaterial and it can be freed.
  185. */
  186. IntMaterial (rampmat.hpp).
  187. /*
  188. * The IntMaterial is derived from an ExtMaterial taking into account the
  189. * driver state when the ExtMaterial was used. Normally IntMaterials are
  190. * on a list in their owning ExtMaterial. If the external material is
  191. * destroyed, any active internal materials which it owned are
  192. * transferred to an orphans list in the driver. This is cleared out
  193. * next time Clear is called.
  194. *
  195. * The internal material has a list of underlying RampMaterials. For
  196. * a non-textured material, there is exactly one and for a textured
  197. * material, there is one per color in the texture's palette. The
  198. * ramp materials track color sharing between internal materials and
  199. * handle the details of allocating color resources.
  200. *
  201. * Internal materials are also chained onto one of a number of lists
  202. * based on their age. The age of a material is the number of frames
  203. * since it was last used to render something. When a material is
  204. * aged, it is rejuvenated by moving it to the age=0 list. Each
  205. * frame, the lists are rotated by one notch and materials on the
  206. * oldest list are reclaimed.
  207. *
  208. * A material is either active or inactive. Active materials have
  209. * color resources and are either on the age=0 list (active this
  210. * frame) or the age=1 list (active last frame). When an inactive
  211. * material is used, it allocates color resources by attempting to
  212. * activate the underlying ramp materials.
  213. *
  214. * At the end of the frame, on Update, any active materials on the
  215. * age=1 list must be materials which were active last frame but were
  216. * not used this frame. We remove their color resources by
  217. * deactivating the underlying ramp materials.
  218. */
  219. RampMaterial (rampmat.hpp).
  220. /*
  221. * RampMaterials are used by internal materials to represent ranges of
  222. * colors. They perform low level color allocation by allocating
  223. * color ranges (RLDDIRamps) from a rampmap.
  224. *
  225. * A textured internal material can use many ramp materials.
  226. * Several internal materials can use the same ramp material if the
  227. * colors match. This can happen easily if many textures use the same
  228. * palette. The ramp material maintains a usage of how many internal
  229. * materials are using it and is freed when the last one stops.
  230. *
  231. * Ramp materials, like internal materials are either active or
  232. * inactive. Active materials have color resources and inactive
  233. * materials do not. A ramp material is made active when any of its
  234. * internal material users are active and inactive when none of then
  235. * are active. To track this a count of how many active users is
  236. * maintained.
  237. *
  238. * When a material is made active, it attempts to allocate a color
  239. * range to use. If that is successful, it sets the colors in the
  240. * range to an appropriate ramp of colors. If is no more space in the
  241. * colormap for a new range, it finds the closes active ramp material
  242. * and shares its ramp.
  243. *
  244. * To track active materials and sharing materials, the driver has a
  245. * list of active materials and each material has a list of sharers.
  246. * The sharers list is only valid for materials which are both active
  247. * and which own their ramp.
  248. */
  249. RLDDIColormap (cmap.h). Common name cmap. Holds pointer to a
  250. RLDDIColorAllocator, and cmap->priv->map is the master 32K pixelmap.
  251. RLDDIRamp (rampmap.h). Common name ramp. Is an element of a RLDDIRampmap
  252. circular queue, and consists of a base (int), size (int), and free (int, BOOL
  253. in meaning) elements. It is used to allocate space in the master pixelmap.
  254. RLDDIRampmap (rampmap.h). Common name rampmap. Holds circular queues of
  255. RLDDIRamp objects on free and allocated lists. It also holds a pointer back to
  256. the cmap object.
  257. RLDDIPalette (palette.h). Common name pal. Holds palette entries, a list of
  258. free palette entries, and methods to allocate, set, and free colors.
  259. A Day in the Life of a Ramp
  260. ===========================
  261. At the beginning of time, RLDDIRampCreate (rampmat.cpp) is called. This
  262. creates and initializes a RLDDIRampLightingDriver with its embedded
  263. RLDDISoftLightingDriver. The structure is zeroed, then the lists and hash
  264. table is initialized. Then InitRampmap is called. If the output surface is
  265. PALETTE4 or PALETTE8, RLDDICreatePalette (palette.cpp) is used to create a 16
  266. or 256 palette in driver->palette. Otherwise, RLDDICreateRGBMap (rgbmap.cpp)
  267. is called to create driver->rgbmap. An rgbmap is just the masks and shifts
  268. necessary to turn an arbitrary 24 bit RGB color into its nearest equivalent in
  269. the output surface format. Thus, rgbmap->alloc.allocate_color doesn't actually
  270. allocate anything, it just returns the nearest output color to the input 24 bit
  271. RGB color.
  272. Once an RLDDIColorAllocator (refered to by alloc) is obtained, a
  273. RLDDICreateIndirectColormap of static size 32K (the max possible, since color
  274. indices in DX5 and DX6 code are 1.15.16) is created. A RLDDIColormap called
  275. cmap is created, and alloc is used to fill the entire 32K entries with black.
  276. Then, RLDDIIndirectColormapGetMap is used to access the actual color map we
  277. malloc'ed and filled with black (cmap->priv->map), and a pointer to this master
  278. 32K array of DWORDS is pointed to by driver->pixelmap and pCtx->pRampMap.
  279. Thus, pCtx->pRampMap is used to do the final color dereference in the ramp
  280. rasterizers.
  281. Then, RLDDICreateRampmap (rampmap.cpp) is use to create a RLDDIRampmap
  282. (called rampmap) and its initial RLDDIRamp (called ramp).
  283. Then, we are finally finished with RLDDIRampCreate.
  284. Next, we would expect to see 1 or more RLDDIRampCreateMaterial's. I take this
  285. opportunity to fill driver->fog_enable, fog_color with the current renderstate
  286. values. D3DIF keeps these, along with driver->driver.ambient (represents
  287. D3DLIGHTSTATE_AMBIENT) up to date. Then, we create a new ExtMaterial (extmat),
  288. and add this material to the drivers->materials list. This list is currently
  289. used for cleanup and material handle lookup. We intend to get rid of the
  290. material handle lookup by forming an association in the runtime. We end by
  291. initializing the ExtMaterial's copy of the D3DMATERIAL for this material with
  292. extmat->SetMaterial.
  293. The next thing that should happen is RLDDIRampSetMaterial should be called.
  294. This is not what happens when a material changes, for that,
  295. RLDDIRampMaterialChanged is called. RLDDIRampSetMaterial sets the
  296. driver->current_material for later activation, and is called when the
  297. D3DLIGHTSTATE_MATERIAL is set.
  298. Note that nothing much has really happened yet. Next, setup (the rampspan
  299. rasterizer, right now) innocently calls a RAMP_SERVICE_FIND_LIGHTINGRANGE
  300. service to find what its ramp base, size, and texture ramp are. This calls
  301. driver->current_material->FindLightingRange, and causes the ramp to actually be
  302. created. First, ExtMaterial::FindIntMaterial is called to find the internal
  303. material that matches the external material's current characteristics. If
  304. there is no matching IntMaterial (initially there are no internal materials),
  305. one is created. Next we create an array of RampMaterial's.
  306. If we are texture mapping, we create 1 RampMaterial* for every color in the
  307. texture palette. We also create an array of longs called "colors" that is the
  308. same size as the texture palette, and will end up being pointed to by
  309. pTex->pRampmap where it will be used as the final dereference in the ramp
  310. rasterizer texture read functions. Then, for each color in the texture
  311. palette, a temporary material is created in which the current material's
  312. ambient and diffuse factors are modulated by the texture palette color. Note
  313. that this implies that the one and only supported texture function for ramp is
  314. modulate, unless the user asks for D3DTBLEND_COPY (I assume we will support
  315. this with another bead, at some point). Then RampMaterial::Find is called to
  316. find or create a matching RampMaterial*. Here is where a hash comes in.
  317. RampMaterial's are hashed based on material diffuse color for fast lookup. If
  318. a perfectly matching RampMaterial is found, it is used, otherwise, a new
  319. RampMaterial with the given D3DMATERIAL is created. At this point the array of
  320. RampMaterial's is just acting like an array of D3DMATERIAL's with hash values.
  321. Now we are done with the construction of IntMaterial, and IntMaterial has all
  322. the RampMaterial's it needs to create all the pixelmaps, rampmaps, etc. we will
  323. need to actually draw a picture.
  324. The non-texture mapped case is the same as above, except only one RampMaterial
  325. is created (for the current one and only D3DMATERIAL associated with this
  326. RampMaterial).
  327. Next, in ExtMaterial::FindLightingRange, after an IntMaterial has been found or
  328. created, IntMaterial::FindLightingRange is called. The first thing IntMaterial
  329. does is see if it is active. If it is, Active() need only update the age lists
  330. so it stays active. Otherwise, as will happen the first time through, we must
  331. activate the material.
  332. Now RampMaterial::Activate is called for each individual RampMaterial. This
  333. calls RampMaterial::AllocateColors. This calls RLDDIRampmapAllocate with the
  334. driver->rampmap to allocate some space in the global pixelmap with a new or
  335. used (but free) RLDDIRamp. Remember, RLDDIRamp's in RLDDIRampmap's are just
  336. for bookkeeping, they don't really store anything. Then we call
  337. RampMaterial::SetColors which calls RampMaterial::SetColorsFog or
  338. RampMaterial::SetColorsStd. This finally calls cmap->set_color which sets the
  339. appropriate entry in the global pixelmap (that we allocated with the
  340. RLDDIRampmap) with the alloc function discussed above. For non-palletized
  341. output surfaces, this just makes an output color given 24 bits of r, g, and b
  342. and the surface's color masks. For palletized output surfaces, this calls
  343. RLDDIPaletteAllocateColor in palette.c, which uses the following basic
  344. algorithm.
  345. If an exact match to the desired color already exists in the surfaces palette,
  346. cool, return it. Otherwise, if there are unused palette entries in the
  347. surface, make one that matches perfectly. Otherwise, find the closest matching
  348. color in the palette (uses dr*dr + dg*dg + db*db where dr = r - palette->r as a
  349. metric) and return that.
  350. It is probably worth mentioning here that only a shadow copy of the surfaces
  351. palette, driver->ddpalette is updated by the palette.cpp SetColor function.
  352. The palette gets updated in the direct draw output surface by
  353. RLDDIUpdateDDPalette.
  354. To delete a material, RLDDIRampDestroyMaterial is called. First, the
  355. ExtMaterial destructor is called. If an IntMaterial associated with the
  356. ExtMaterial is still active, the IntMaterial is placed on the driver->orphans
  357. list. Orphans are cleaned up when RLDDIRampBeginSceneHook is called, or when
  358. RLDDIRampDestroy is called to destroy the whole RLDDIRampLightingDriver.
  359. Stuff We Do Different (from DX5)
  360. ================================
  361. The initialization code in InitRampmap (rampmat.cpp) is all of private
  362. interpretation, mostly from the DX5 source drivers\win32\ddraw.c. This code
  363. could not be literally stolen, since it brings in a whole bunch of undesirable
  364. RLDDI stuff.
  365. RLDDIUpdateDDPalette (palette.cpp) is likewise from DX5 source
  366. drivers\win32\ddraw.c. I'm not sure where this was ever called in DX5, but I
  367. have put it sucessfully (so far) in rampif.cpp after all FindLightingRange's
  368. (which is the only thing that can change the palette to change).
  369. Issues
  370. ======
  371. RLDDIRampEndSceneHook is not being called. This constitutes a memory leak.
  372. Need to move the association of the ExtMaterial's with hMat's to the runtime.
  373. Hacked DrawPrim ramp lighting is not the same as RenderPrim (halexe.cpp).
  374. Probably don't need to fix this if Iouri does lighting.
  375. Apps that interpolate across vertices from different materials, like oct1 and
  376. twist may not look exactly the same as they did on DX5, since the appearance
  377. will depend on where the material got put in the global pixelmap. This, in
  378. turn, depends on the exact timing of the RLDDIRampBeginSceneHook,
  379. RLDDIRampEndSceneHook calls, which we will not reasonably be able to reproduce.
  380. Apps Compat
  381. ===========
  382. NT below means NT 5. 98 means memphis.
  383. Direct3D\TestApps\D3DIm
  384. flipcube.exe O.K. on NT/98
  385. oct1.exe O.K. on NT/98
  386. oct2.exe O.K. on NT/98
  387. sphere.exe O.K. on NT/98
  388. triangle.exe O.K. on NT/98
  389. tunnel.exe O.K. on NT/98 Hit F9 3 times to see glitchy problem
  390. with grid texture. Problem only exists in ramp.
  391. twist.exe O.K. on NT/98
  392. Direct3D\TestApps\D3DRm
  393. egg.exe O.K. on NT/98
  394. faces.exe O.K. on NT/98
  395. fly.exe O.K. on NT/98
  396. globe.exe O.K. on NT/98
  397. globe2.exe O.K. on NT/98
  398. hier1.exe O.K. on NT/98
  399. hier2.exe O.K. on NT/98
  400. quat.exe O.K. on NT/98
  401. shadow.exe O.K. on NT/98
  402. tex1.exe O.K. on NT/98
  403. tex3.exe O.K. on NT/98
  404. tex4.exe O.K. on NT/98
  405. tex5.exe O.K. on NT/98
  406. trans.exe O.K. on NT/98
  407. uvis.exe O.K. on NT/98
  408. viewer.exe O.K. on NT/98
  409. Other
  410. wipeout2.exe O.K. on NT/98
  411. hyperblade (win95 only) always uses its own rendering or hardware
  412. wargods (win95 only) always works, seems to not be using
  413. rasterizers.
  414. agile warrior (win95 only) O.K.
  415. terracide (win95 only) Shows perspectivish problem that can get
  416. quite pronounced at times.